diff options
author | Jeka | 2024-04-04 22:36:32 +0300 |
---|---|---|
committer | Jeka | 2024-04-04 22:36:32 +0300 |
commit | a9fcf6eb146bb99793f85b26567c1d3b350e5542 (patch) | |
tree | 8d60933b0965110cdd206620096683c0e6aa8e58 | |
parent | 5429f4e1a3b9df2f007432bf0d4096447d3eb22e (diff) | |
download | aur-a9fcf6eb146bb99793f85b26567c1d3b350e5542.tar.gz |
kernel release 6.6.25
20 files changed, 3362 insertions, 3047 deletions
@@ -1,6 +1,6 @@ pkgbase = linux-jcore pkgdesc = Kernel for Manjaro/EndeavourOS/Arch (ACS override patch include) - pkgver = 6.6.6 + pkgver = 6.6.25 pkgrel = 2 url = https://www.kernel.org/ arch = x86_64 @@ -21,18 +21,15 @@ pkgbase = linux-jcore replaces = linux-acs-manjaro replaces = linux-acs-manjaro-headers options = !strip - source = https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.6.6.tar.xz + source = https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.6.25.tar.xz source = config source = 0101-ZEN_Add_sysctl_and_CONFIG_to_disallow_unprivileged_CLONE_NEWUSER.patch source = 0102-drivers-firmware-skip-simpledrm-if-nvidia-drm.modese.patch source = 0999-patch_realtek.patch - source = 0000-hid-asus-add-const-to-read-only-outgoing-usb-buffer.patch - source = 0001-hid-asus-reset-the-backlight-brightness-level-on-resume.patch - source = v14.1-0001-HID-asus-fix-more-n-key-report-descriptors-if-.patch - source = v14.1-0002-HID-asus-make-asus_kbd_init-generic-remove-rog.patch - source = v14.1-0003-HID-asus-add-ROG-Ally-N-Key-ID-and-keycodes.patch - source = v14.1-0004-HID-asus-add-ROG-Ally-xpad-settings.patch - source = v14.1-fix-defaults1.patch + source = v14.7-0001-HID-asus-fix-more-n-key-report-descriptors-if-.patch + source = v14.7-0002-HID-asus-make-asus_kbd_init-generic-remove-rog.patch + source = v14.7-0003-HID-asus-add-ROG-Ally-N-Key-ID-and-keycodes.patch + source = v14.7-0004-HID-asus-add-ROG-Ally-xpad-settings.patch source = 0006-platform-x86-asus-wmi-disable-USB0-hub-on-ROG-Ally-b.patch source = 0007-mt7921e_Perform_FLR_to_recovery_the_device.patch source = 0301-drm-Add_GPU_reset_sysfs_event.patch @@ -41,21 +38,23 @@ pkgbase = linux-jcore source = 0001-ALSA-hda-cs35l41-Support-ASUS-2023-laptops-with-miss.patch source = 0001-ALSA-hda-cs35l41-Improve-support-for-ASUS-ROG-Ally.patch source = ROG-ALLY-NCT6775-PLATFORM.patch - source = 0001-ROG-ALLY-bmi323-device.patch + source = 0001-iio-imu_Add_driver_for_BMI323_IMU.patch + source = 0002-iio-imu-bmi323-Make-the-local-structures-static.patch + source = 0003-iio-imu_Add_ROG_ALLY_bmi323-support.patch + source = 0004-iio-imu-Load_ROG_ALLY_mount_matrix.patch + source = 0005-iio-imu-ASUS-ROG-ALLY-force-INT1-IRQ.patch source = 0001-HID.patch + source = 0001-OrangePi-Neo-panel-orientation-quirk.patch source = 0999-acs.gitpatch - sha256sums = ebf70a917934b13169e1be5b95c3b6c2fea5bc14e6dc144f1efb8a0016b224c8 - sha256sums = 043ada1688a42e652bb0b339d2f9732c323c22da96bb2ca2bcf144a731c5e981 + sha256sums = 99d210be87908233a55b0fadc0dccd3b95926c0651b6b82e37350b2029de1f44 + sha256sums = 9736c7856f4dd543d2172e1cb8a63cabdd6ed6fbf314dfdb5fe4c60b74954a68 sha256sums = 05f04019d4a2ee072238c32860fa80d673687d84d78ef436ae9332b6fb788467 sha256sums = e1d17690dd21e8d5482b63ca66bfe6b478d39e8e8b59eedd53adb0a55ebc308d - sha256sums = 3aa9f1ca47bb078f3c9a52fe61897cf4fe989068cd7e66bfa6644fd605fa40d2 - sha256sums = fb2cd8a3ea9d47bd78c99b8ece1f3959c20b4de97a7959a12650f989f5c724da - sha256sums = 7f3194f1a7c5ebc27bbfa4559cfd9a2ccffddbbd2d259c0d9c68631cb66c5855 - sha256sums = 176adde8fc3069bd28393bf0c9d788f1b0f9a186678aec4dc17b0b081c57f97b - sha256sums = 493fa177cf602f087e981e95fad3764e305f4c486d4c2ef78255388b913be9cf - sha256sums = 50ea381758fb8a8566f38a509fe7cf0448c77eaec5103066cafc2ecf02db1e9f - sha256sums = 970687b811034e722befde62bcf6d51c7442a217074ed0fb71460bb1803f4c64 - sha256sums = c00b23162fdbf50de375d8e444b6d59e2e3630cfac55ec1d06114b9dad00e542 + sha256sums = a99b684fe5bc7fdacc6f5b1f2b6593672fc5d1e676c4de03ec29723747fc574b + sha256sums = b099ae83a3b561b8bff8b32b44b6f4835b99eb150c2314177aa0bc8ca96e2ead + sha256sums = 10b60663195a65ec3b0f50b49e4c0af952369ee5afe95e11a69ffccefc020eb2 + sha256sums = 3c8b877dfaf85acf45b54c85a44fa269aa1512ea3781fe551cf6d4e2d69c992d + sha256sums = 73aa4be8c1abcf1b24c9a5c5072e68da3da82df807f3ff49660a100d7634da1d sha256sums = 836e88044263f7bc474ca466b3d0d98c39e265db94925c300d0b138492946a13 sha256sums = d673d034fbcd80426fd8d9c6af56537c5fe5b55fe49d74e313474d7fc285ecc1 sha256sums = 1f62542a889a6c2eafd43acd0699f54720ed891eeda66a4a9261d75b92f28b7f @@ -64,8 +63,13 @@ pkgbase = linux-jcore sha256sums = 79970a4729572cb25fd4644d66f38ecd5b3e1610a42ea4bbe436b501f3469fa2 sha256sums = 430a7f971d78d0873708e0ad38fba602ceafefd4da8ebbf9d9c591bc4799acb5 sha256sums = cfcd5c177423df8b7b98b0500fe7ab0757f895ed945c33e205963f0069c7a3be - sha256sums = 5574a68b1c7733769835bb856a8c32e54398dfde59f264708672b87b73b3c6ea + sha256sums = 708a9899f80db35fb0f06e0144c361eac9a9b2d154cf2fa388a0b4810847e24c + sha256sums = 514fd03c17245ed0aaee63e8830c9b02b00efa0307f7e0989065edec6ae185f0 + sha256sums = fccdf24b25620dd8271bb3b52ddc53f8882dec26518258dc47e1469fed33e516 + sha256sums = c3b901db58288b5cc5d8a947ac8ffec339870b00aba493d68a39f65c4ff3d869 + sha256sums = 5792a59a0c726a205ae1c1728700ea3e6385231cadc2cfdd2db08295b100638c sha256sums = 7c948773d758418d8a436067265d678c444827562c46b9fced2ff31ced108481 + sha256sums = aa2ff6edca0177b864868fdc2752d3a0eaaf5b801bd17e5c59dfd78999226d83 sha256sums = 458d7e024d33d4965b14b9b987f01a2884ff28761cff5da7c6a54132a95e9f36 pkgname = linux-jcore diff --git a/0000-hid-asus-add-const-to-read-only-outgoing-usb-buffer.patch b/0000-hid-asus-add-const-to-read-only-outgoing-usb-buffer.patch deleted file mode 100644 index 3bf969bb1709..000000000000 --- a/0000-hid-asus-add-const-to-read-only-outgoing-usb-buffer.patch +++ /dev/null @@ -1,57 +0,0 @@ -From 06ae5afce8cc1f7621cc5c7751e449ce20d68af7 Mon Sep 17 00:00:00 2001 -From: Denis Benato <benato.denis96@gmail.com> -Date: Fri, 17 Nov 2023 14:15:55 +1300 -Subject: [PATCH] HID: hid-asus: add const to read-only outgoing usb buffer - -In the function asus_kbd_set_report the parameter buf is read-only -as it gets copied in a memory portion suitable for USB transfer, -but the parameter is not marked as const: add the missing const and mark -const immutable buffers passed to that function. - -Signed-off-by: Denis Benato <benato.denis96@gmail.com> -Signed-off-by: Luke D. Jones <luke@ljones.dev> -Signed-off-by: Jiri Kosina <jkosina@suse.cz> ---- - drivers/hid/hid-asus.c | 8 ++++---- - 1 file changed, 4 insertions(+), 4 deletions(-) - -diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c -index fd61dba882338e..b70673a929a1ed 100644 ---- a/drivers/hid/hid-asus.c -+++ b/drivers/hid/hid-asus.c -@@ -381,7 +381,7 @@ static int asus_raw_event(struct hid_device *hdev, - return 0; - } - --static int asus_kbd_set_report(struct hid_device *hdev, u8 *buf, size_t buf_size) -+static int asus_kbd_set_report(struct hid_device *hdev, const u8 *buf, size_t buf_size) - { - unsigned char *dmabuf; - int ret; -@@ -404,7 +404,7 @@ static int asus_kbd_set_report(struct hid_device *hdev, u8 *buf, size_t buf_size - - static int asus_kbd_init(struct hid_device *hdev) - { -- u8 buf[] = { FEATURE_KBD_REPORT_ID, 0x41, 0x53, 0x55, 0x53, 0x20, 0x54, -+ const u8 buf[] = { FEATURE_KBD_REPORT_ID, 0x41, 0x53, 0x55, 0x53, 0x20, 0x54, - 0x65, 0x63, 0x68, 0x2e, 0x49, 0x6e, 0x63, 0x2e, 0x00 }; - int ret; - -@@ -418,7 +418,7 @@ static int asus_kbd_init(struct hid_device *hdev) - static int asus_kbd_get_functions(struct hid_device *hdev, - unsigned char *kbd_func) - { -- u8 buf[] = { FEATURE_KBD_REPORT_ID, 0x05, 0x20, 0x31, 0x00, 0x08 }; -+ const u8 buf[] = { FEATURE_KBD_REPORT_ID, 0x05, 0x20, 0x31, 0x00, 0x08 }; - u8 *readbuf; - int ret; - -@@ -449,7 +449,7 @@ static int asus_kbd_get_functions(struct hid_device *hdev, - - static int rog_nkey_led_init(struct hid_device *hdev) - { -- u8 buf_init_start[] = { FEATURE_KBD_LED_REPORT_ID1, 0xB9 }; -+ const u8 buf_init_start[] = { FEATURE_KBD_LED_REPORT_ID1, 0xB9 }; - u8 buf_init2[] = { FEATURE_KBD_LED_REPORT_ID1, 0x41, 0x53, 0x55, 0x53, 0x20, - 0x54, 0x65, 0x63, 0x68, 0x2e, 0x49, 0x6e, 0x63, 0x2e, 0x00 }; - u8 buf_init3[] = { FEATURE_KBD_LED_REPORT_ID1, diff --git a/0001-OrangePi-Neo-panel-orientation-quirk.patch b/0001-OrangePi-Neo-panel-orientation-quirk.patch new file mode 100644 index 000000000000..ad04ec936ede --- /dev/null +++ b/0001-OrangePi-Neo-panel-orientation-quirk.patch @@ -0,0 +1,15 @@ +--- linux-6.7/drivers/gpu/drm/drm_panel_orientation_quirks.c 2024-02-16 14:35:44.755058457 +0700 ++++ linux-6.7/drivers/gpu/drm/drm_panel_orientation_quirks.c 2024-02-16 14:34:26.391114606 +0700 +@@ -396,6 +396,12 @@ static const struct dmi_system_id orient + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "ONE XPLAYER"), + }, + .driver_data = (void *)&lcd1600x2560_leftside_up, ++ }, { /* OrangePi Neo */ ++ .matches = { ++ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "OrangePi"), ++ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "NEO-01"), ++ }, ++ .driver_data = (void *)&lcd1200x1920_rightside_up, + }, { /* Samsung GalaxyBook 10.6 */ + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), diff --git a/0001-ROG-ALLY-bmi323-device.patch b/0001-ROG-ALLY-bmi323-device.patch deleted file mode 100644 index e83d6e3e1830..000000000000 --- a/0001-ROG-ALLY-bmi323-device.patch +++ /dev/null @@ -1,2672 +0,0 @@ -From 622ea77bfccd751247b1c08c3126d7ab716f0423 Mon Sep 17 00:00:00 2001 -From: Denis <benato.denis96@gmail.com> -Date: Mon, 25 Sep 2023 03:38:49 +0200 -Subject: [PATCH] This commit adds support to the bmi323 device on top of the - pre-existing bmc150 kernel module. - -Some new devices for example the ROG Ally and the Air Plus identify this chip in the ACPI table as a bmc150 so previously the original module was loaded, -but was erroring out as it cannot handle such device. - -The device I own does not allow me to use the interrupt part of the device as the interrupt pin is not connected (or not advertised to be connected) hence -I avoided including on this commit anything related to IRQ. - -This driver has already been proved to work well enough to be used in the switch emulator "yuzu". - -While designing this module my main focus was not to alter the original driver and not to limit the original author in regard to future mofications, -and I was mostly able to achive this, except: -1) I added a new structure on top of the original one and added a field that is responsible for holding information -on what type of chip the module is currently managing -2) the previous point required the init function of the original driver to write that field in order to be sure no bmi323 code -was executed when the old part of the module is managing the device -3) as the original driver issued an i2c write on some register not really meant to be written in the bmi323 device I have made sure an i2c read to discover -the bmi323 is performed prior to that code: such read SHOULD fail in the older bmc150 IC for two reasons: - - the i2c address is not reported in the memory map of the bmc150 in its datasheet - - the i2c read attempts to get 4 bytes out of a 8-bit device - - the fourth bit (the one that cannot be read from a bmc150 device) is initialized to 0 and bmi323 presence is signaled with a 1 in the LSB - that is the fourth coming out of the device in temporal order ---- - drivers/iio/accel/bmc150-accel-core.c | 2307 ++++++++++++++++++++++++- - drivers/iio/accel/bmc150-accel-i2c.c | 100 +- - drivers/iio/accel/bmc150-accel.h | 94 +- - 3 files changed, 2495 insertions(+), 6 deletions(-) - -diff --git a/drivers/iio/accel/bmc150-accel-core.c b/drivers/iio/accel/bmc150-accel-core.c -index 110591804b4c..9a2c1732c9ef 100644 ---- a/drivers/iio/accel/bmc150-accel-core.c -+++ b/drivers/iio/accel/bmc150-accel-core.c -@@ -130,6 +130,73 @@ - #define BMC150_ACCEL_REG_FIFO_DATA 0x3F - #define BMC150_ACCEL_FIFO_LENGTH 32 - -+#define BMC150_BMI323_TEMPER_CENTER_VAL 23 -+#define BMC150_BMI323_TEMPER_LSB_PER_KELVIN_VAL 512 -+ -+#define BMC150_BMI323_AUTO_SUSPEND_DELAY_MS 2000 -+ -+#define BMC150_BMI323_CHIP_ID_REG 0x00 -+#define BMC150_BMI323_SOFT_RESET_REG 0x7E -+#define BMC150_BMI323_SOFT_RESET_VAL 0xDEAFU -+#define BMC150_BMI323_DATA_BASE_REG 0x03 -+#define BMC150_BMI323_TEMPERATURE_DATA_REG 0x09 -+#define BMC150_BMI323_FIFO_FILL_LEVEL_REG 0x15 -+#define BMC150_BMI323_FIFO_DATA_REG 0x16 -+#define BMC150_BMI323_ACC_CONF_REG 0x20 -+#define BMC150_BMI323_GYR_CONF_REG 0x21 -+#define BMC150_BMI323_FIFO_CONF_REG 0x36 -+ -+// these are bits [0:3] of ACC_CONF.acc_odr, sample rate in Hz for the accel part of the chip -+#define BMC150_BMI323_ACCEL_ODR_0_78123_VAL 0x0001 -+#define BMC150_BMI323_ACCEL_ODR_1_5625_VAL 0x0002 -+#define BMC150_BMI323_ACCEL_ODR_3_125_VAL 0x0003 -+#define BMC150_BMI323_ACCEL_ODR_6_25_VAL 0x0004 -+#define BMC150_BMI323_ACCEL_ODR_12_5_VAL 0x0005 -+#define BMC150_BMI323_ACCEL_ODR_25_VAL 0x0006 -+#define BMC150_BMI323_ACCEL_ODR_50_VAL 0x0007 -+#define BMC150_BMI323_ACCEL_ODR_100_VAL 0x0008 -+#define BMC150_BMI323_ACCEL_ODR_200_VAL 0x0009 -+#define BMC150_BMI323_ACCEL_ODR_400_VAL 0x000A -+#define BMC150_BMI323_ACCEL_ODR_800_VAL 0x000B -+#define BMC150_BMI323_ACCEL_ODR_1600_VAL 0x000C -+#define BMC150_BMI323_ACCEL_ODR_3200_VAL 0x000D -+#define BMC150_BMI323_ACCEL_ODR_6400_VAL 0x000E -+ -+#define BMC150_BMI323_ACCEL_BW_ODR_2_VAL 0x0000 -+#define BMC150_BMI323_ACCEL_BW_ODR_4_VAL 0x0001 -+ -+// these are bits [4:6] of ACC_CONF.acc_range, full scale resolution -+#define BMC150_BMI323_ACCEL_RANGE_2_VAL 0x0000 // +/-2g, 16.38 LSB/mg -+#define BMC150_BMI323_ACCEL_RANGE_4_VAL 0x0001 // +/-4g, 8.19 LSB/mg -+#define BMC150_BMI323_ACCEL_RANGE_8_VAL 0x0002 // +/-8g, 4.10 LSB/mg -+#define BMC150_BMI323_ACCEL_RANGE_16_VAL 0x0003 // +/-4g, 2.05 LSB/mg -+ -+// these are bits [0:3] of GYR_CONF.gyr_odr, sample rate in Hz for the gyro part of the chip -+#define BMC150_BMI323_GYRO_ODR_0_78123_VAL 0x0001 -+#define BMC150_BMI323_GYRO_ODR_1_5625_VAL 0x0002 -+#define BMC150_BMI323_GYRO_ODR_3_125_VAL 0x0003 -+#define BMC150_BMI323_GYRO_ODR_6_25_VAL 0x0004 -+#define BMC150_BMI323_GYRO_ODR_12_5_VAL 0x0005 -+#define BMC150_BMI323_GYRO_ODR_25_VAL 0x0006 -+#define BMC150_BMI323_GYRO_ODR_50_VAL 0x0007 -+#define BMC150_BMI323_GYRO_ODR_100_VAL 0x0008 -+#define BMC150_BMI323_GYRO_ODR_200_VAL 0x0009 -+#define BMC150_BMI323_GYRO_ODR_400_VAL 0x000A -+#define BMC150_BMI323_GYRO_ODR_800_VAL 0x000B -+#define BMC150_BMI323_GYRO_ODR_1600_VAL 0x000C -+#define BMC150_BMI323_GYRO_ODR_3200_VAL 0x000D -+#define BMC150_BMI323_GYRO_ODR_6400_VAL 0x000E -+ -+#define BMC150_BMI323_GYRO_BW_ODR_2_VAL 0x0000 -+#define BMC150_BMI323_GYRO_BW_ODR_4_VAL 0x0001 -+ -+// these are bits [4:6] of GYR_CONF.gyr_range, full scale resolution -+#define BMC150_BMI323_GYRO_RANGE_125_VAL 0x0000 // +/-125°/s, 262.144 LSB/°/s -+#define BMC150_BMI323_GYRO_RANGE_250_VAL 0x0001 // +/-250°/s, 131.2 LSB/°/s -+#define BMC150_BMI323_GYRO_RANGE_500_VAL 0x0002 // +/-500°/s, 65.6 LSB/°/s -+#define BMC150_BMI323_GYRO_RANGE_1000_VAL 0x0003 // +/-1000°/s, 32.8 LSB/°/s -+#define BMC150_BMI323_GYRO_RANGE_2000_VAL 0x0004 // +/-2000°/s, 16.4 LSB/°/s -+ - enum bmc150_accel_axis { - AXIS_X, - AXIS_Y, -@@ -149,6 +216,654 @@ struct bmc150_scale_info { - u8 reg_range; - }; - -+/* -+ * This enum MUST not be altered as there are parts in the code that -+ * uses an int conversion to get the correct device register to read. -+ */ -+enum bmi323_axis { -+ BMI323_ACCEL_AXIS_X = 0, -+ BMI323_ACCEL_AXIS_Y, -+ BMI323_ACCEL_AXIS_Z, -+ BMI323_GYRO_AXIS_X, -+ BMI323_GYRO_AXIS_Y, -+ BMI323_GYRO_AXIS_Z, -+ BMI323_TEMP, -+ BMI323_AXIS_MAX, -+}; -+ -+static const struct bmi323_scale_accel_info { -+ u8 hw_val; -+ int val; -+ int val2; -+ int ret_type; -+} bmi323_accel_scale_map[] = { -+ { -+ .hw_val = (u16)BMC150_BMI323_ACCEL_RANGE_2_VAL << (u16)4, -+ .val = 0, -+ .val2 = 598, -+ .ret_type = IIO_VAL_INT_PLUS_MICRO, -+ }, -+ { -+ .hw_val = (u16)BMC150_BMI323_ACCEL_RANGE_4_VAL << (u16)4, -+ .val = 0, -+ .val2 = 1196, -+ .ret_type = IIO_VAL_INT_PLUS_MICRO, -+ }, -+ { -+ .hw_val = (u16)BMC150_BMI323_ACCEL_RANGE_8_VAL << (u16)4, -+ .val = 0, -+ .val2 = 2392, -+ .ret_type = IIO_VAL_INT_PLUS_MICRO, -+ }, -+ { -+ .hw_val = (u16)BMC150_BMI323_ACCEL_RANGE_16_VAL << (u16)4, -+ .val = 0, -+ .val2 = 4785, -+ .ret_type = IIO_VAL_INT_PLUS_MICRO, -+ }, -+}; -+ -+static const struct bmi323_scale_gyro_info { -+ u8 hw_val; -+ int val; -+ int val2; -+ int ret_type; -+} bmi323_gyro_scale_map[] = { -+ { -+ .hw_val = (u16)BMC150_BMI323_GYRO_RANGE_125_VAL << (u16)4, -+ .val = 0, -+ .val2 = 66545, -+ .ret_type = IIO_VAL_INT_PLUS_NANO, -+ }, -+ { -+ .hw_val = (u16)BMC150_BMI323_GYRO_RANGE_125_VAL << (u16)4, -+ .val = 0, -+ .val2 = 66, -+ .ret_type = IIO_VAL_INT_PLUS_NANO, -+ }, -+ { -+ .hw_val = (u16)BMC150_BMI323_GYRO_RANGE_250_VAL << (u16)4, -+ .val = 0, -+ .val2 = 133090, -+ .ret_type = IIO_VAL_INT_PLUS_NANO, -+ }, -+ { -+ .hw_val = (u16)BMC150_BMI323_GYRO_RANGE_250_VAL << (u16)4, -+ .val = 0, -+ .val2 = 133, -+ .ret_type = IIO_VAL_INT_PLUS_NANO, -+ }, -+ { -+ .hw_val = (u16)BMC150_BMI323_GYRO_RANGE_500_VAL << (u16)4, -+ .val = 0, -+ .val2 = 266181, -+ .ret_type = IIO_VAL_INT_PLUS_NANO, -+ }, -+ { -+ .hw_val = (u16)BMC150_BMI323_GYRO_RANGE_500_VAL << (u16)4, -+ .val = 0, -+ .val2 = 266, -+ .ret_type = IIO_VAL_INT_PLUS_NANO, -+ }, -+ { -+ .hw_val = (u16)BMC150_BMI323_GYRO_RANGE_1000_VAL << (u16)4, -+ .val = 0, -+ .val2 = 532362, -+ .ret_type = IIO_VAL_INT_PLUS_NANO, -+ }, -+ { -+ .hw_val = (u16)BMC150_BMI323_GYRO_RANGE_1000_VAL << (u16)4, -+ .val = 0, -+ .val2 = 532, -+ .ret_type = IIO_VAL_INT_PLUS_NANO, -+ }, -+ { -+ .hw_val = (u16)BMC150_BMI323_GYRO_RANGE_2000_VAL << (u16)4, -+ .val = 0, -+ .val2 = 1064724, -+ .ret_type = IIO_VAL_INT_PLUS_NANO, -+ }, -+ { -+ // this shouldn't be necessary, but iio seems to have a wrong rounding of this value... -+ .hw_val = (u16)BMC150_BMI323_GYRO_RANGE_2000_VAL << (u16)4, -+ .val = 0, -+ .val2 = 1064, -+ .ret_type = IIO_VAL_INT_PLUS_NANO, -+ }, -+ { -+ .hw_val = (u16)BMC150_BMI323_GYRO_RANGE_2000_VAL << (u16)4, -+ .val = 0, -+ .val2 = 1065, -+ .ret_type = IIO_VAL_INT_PLUS_NANO, -+ }, -+}; -+ -+/* -+ * this reflects the frequency map that is following. -+ * For each index i of that map index i*2 and i*2+1 of of this -+ * holds ODR/2 and ODR/4 -+ */ -+static const struct bmi323_3db_freq_cutoff_accel_info { -+ int val; -+ int val2; -+ int ret_type; -+} bmi323_accel_3db_freq_cutoff[] = { -+ { -+ .val = 0, -+ .val2 = 390615, -+ .ret_type = IIO_VAL_INT_PLUS_MICRO, -+ }, -+ { -+ .val = 0, -+ .val2 = 195308, -+ .ret_type = IIO_VAL_INT_PLUS_MICRO, -+ }, -+ { -+ .val = 0, -+ .val2 = 781300, -+ .ret_type = IIO_VAL_INT_PLUS_MICRO, -+ }, -+ { -+ .val = 0, -+ .val2 = 390650, -+ .ret_type = IIO_VAL_INT_PLUS_MICRO, -+ }, -+ { -+ .val = 1, -+ .val2 = 562500, -+ .ret_type = IIO_VAL_INT_PLUS_MICRO, -+ }, -+ { -+ .val = 0, -+ .val2 = 78125, -+ .ret_type = IIO_VAL_INT_PLUS_MICRO, -+ }, -+ { -+ .val = 3, -+ .val2 = 000000, -+ .ret_type = IIO_VAL_INT_PLUS_MICRO, -+ }, -+ { -+ .val = 1, -+ .val2 = 500000, -+ .ret_type = IIO_VAL_INT_PLUS_MICRO, -+ }, -+ { -+ .val = 6, -+ .val2 = 000000, -+ .ret_type = IIO_VAL_INT_PLUS_MICRO, -+ }, -+ { -+ .val = 3, -+ .val2 = 000000, -+ .ret_type = IIO_VAL_INT_PLUS_MICRO, -+ }, -+ { -+ .val = 12, -+ .val2 = 500000, -+ .ret_type = IIO_VAL_INT_PLUS_MICRO, -+ }, -+ { -+ .val = 6, -+ .val2 = 250000, -+ .ret_type = IIO_VAL_INT_PLUS_MICRO, -+ }, -+ { -+ .val = 25, -+ .val2 = 000000, -+ .ret_type = IIO_VAL_INT_PLUS_MICRO, -+ }, -+ { -+ .val = 12, -+ .val2 = 500000, -+ .ret_type = IIO_VAL_INT_PLUS_MICRO, -+ }, -+ { -+ .val = 50, -+ .val2 = 000000, -+ .ret_type = IIO_VAL_INT_PLUS_MICRO, -+ }, -+ { -+ .val = 25, -+ .val2 = 000000, -+ .ret_type = IIO_VAL_INT_PLUS_MICRO, -+ }, -+ { -+ .val = 100, -+ .val2 = 000000, -+ .ret_type = IIO_VAL_INT_PLUS_MICRO, -+ }, -+ { -+ .val = 50, -+ .val2 = 000000, -+ .ret_type = IIO_VAL_INT_PLUS_MICRO, -+ }, -+ { -+ .val = 200, -+ .val2 = 000000, -+ .ret_type = IIO_VAL_INT_PLUS_MICRO, -+ }, -+ { -+ .val = 100, -+ .val2 = 000000, -+ .ret_type = IIO_VAL_INT_PLUS_MICRO, -+ }, -+ { -+ .val = 400, -+ .val2 = 000000, -+ .ret_type = IIO_VAL_INT_PLUS_MICRO, -+ }, -+ { -+ .val = 200, -+ .val2 = 000000, -+ .ret_type = IIO_VAL_INT_PLUS_MICRO, -+ }, -+ { -+ .val = 800, -+ .val2 = 000000, -+ .ret_type = IIO_VAL_INT_PLUS_MICRO, -+ }, -+ { -+ .val = 400, -+ .val2 = 000000, -+ .ret_type = IIO_VAL_INT_PLUS_MICRO, -+ }, -+ { -+ .val = 1600, -+ .val2 = 000000, -+ .ret_type = IIO_VAL_INT_PLUS_MICRO, -+ }, -+ { -+ .val = 800, -+ .val2 = 000000, -+ .ret_type = IIO_VAL_INT_PLUS_MICRO, -+ }, -+ { -+ .val = 1600, -+ .val2 = 000000, -+ .ret_type = IIO_VAL_INT_PLUS_MICRO, -+ }, -+ { -+ .val = 800, -+ .val2 = 000000, -+ .ret_type = IIO_VAL_INT_PLUS_MICRO, -+ }, -+ { -+ .val = 3200, -+ .val2 = 000000, -+ .ret_type = IIO_VAL_INT_PLUS_MICRO, -+ }, -+ { -+ .val = 1600, -+ .val2 = 000000, -+ .ret_type = IIO_VAL_INT_PLUS_MICRO, -+ }, -+}; -+ -+static const struct bmi323_freq_accel_info { -+ u8 hw_val; -+ int val; -+ int val2; -+ s64 time_ns; -+} bmi323_accel_odr_map[] = { -+ { -+ .hw_val = BMC150_BMI323_ACCEL_ODR_0_78123_VAL, -+ .val = 0, -+ .val2 = 781230, -+ .time_ns = 1280032769, -+ }, -+ { -+ .hw_val = BMC150_BMI323_ACCEL_ODR_1_5625_VAL, -+ .val = 1, -+ .val2 = 562600, -+ .time_ns = 886522247, -+ }, -+ { -+ .hw_val = BMC150_BMI323_ACCEL_ODR_3_125_VAL, -+ .val = 3, -+ .val2 = 125000, -+ .time_ns = 320000000, -+ }, -+ { -+ .hw_val = BMC150_BMI323_ACCEL_ODR_6_25_VAL, -+ .val = 6, -+ .val2 = 250000, -+ .time_ns = 160000000, -+ }, -+ { -+ .hw_val = BMC150_BMI323_ACCEL_ODR_12_5_VAL, -+ .val = 12, -+ .val2 = 500000, -+ .time_ns = 80000000, -+ }, -+ { -+ .hw_val = BMC150_BMI323_ACCEL_ODR_25_VAL, -+ .val = 25, -+ .val2 = 0, -+ .time_ns = 40000000, -+ }, -+ { -+ .hw_val = BMC150_BMI323_ACCEL_ODR_50_VAL, -+ .val = 50, -+ .val2 = 0, -+ .time_ns = 20000000, -+ }, -+ { -+ .hw_val = BMC150_BMI323_ACCEL_ODR_100_VAL, -+ .val = 100, -+ .val2 = 0, -+ .time_ns = 10000000, -+ }, -+ { -+ .hw_val = BMC150_BMI323_ACCEL_ODR_200_VAL, -+ .val = 200, -+ .val2 = 0, -+ .time_ns = 5000000, -+ }, -+ { -+ .hw_val = BMC150_BMI323_ACCEL_ODR_400_VAL, -+ .val = 400, -+ .val2 = 0, -+ .time_ns = 2500000, -+ }, -+ { -+ .hw_val = BMC150_BMI323_ACCEL_ODR_800_VAL, -+ .val = 800, -+ .val2 = 0, -+ .time_ns = 1250000, -+ }, -+ { -+ .hw_val = BMC150_BMI323_ACCEL_ODR_1600_VAL, -+ .val = 1600, -+ .val2 = 0, -+ .time_ns = 625000, -+ }, -+ { -+ .hw_val = BMC150_BMI323_ACCEL_ODR_3200_VAL, -+ .val = 3200, -+ .val2 = 0, -+ .time_ns = 312500, -+ }, -+ { -+ .hw_val = BMC150_BMI323_ACCEL_ODR_6400_VAL, -+ .val = 6400, -+ .val2 = 0, -+ .time_ns = 156250, -+ }, -+}; -+ -+static const struct bmi323_freq_gyro_info { -+ u8 hw_val; -+ int val; -+ int val2; -+ s64 time_ns; -+} bmi323_gyro_odr_map[] = { -+ { -+ .hw_val = BMC150_BMI323_GYRO_ODR_0_78123_VAL, -+ .val = 0, -+ .val2 = 781230, -+ .time_ns = 1280032769, -+ }, -+ { -+ .hw_val = BMC150_BMI323_GYRO_ODR_1_5625_VAL, -+ .val = 1, -+ .val2 = 562600, -+ .time_ns = 886522247, -+ }, -+ { -+ .hw_val = BMC150_BMI323_GYRO_ODR_3_125_VAL, -+ .val = 3, -+ .val2 = 125000, -+ .time_ns = 320000000, -+ }, -+ { -+ .hw_val = BMC150_BMI323_GYRO_ODR_6_25_VAL, -+ .val = 6, -+ .val2 = 250000, -+ .time_ns = 160000000, -+ }, -+ { -+ .hw_val = BMC150_BMI323_GYRO_ODR_12_5_VAL, -+ .val = 12, -+ .val2 = 500000, -+ .time_ns = 80000000, -+ }, -+ { -+ .hw_val = BMC150_BMI323_GYRO_ODR_25_VAL, -+ .val = 25, -+ .val2 = 0, -+ .time_ns = 40000000, -+ }, -+ { -+ .hw_val = BMC150_BMI323_GYRO_ODR_50_VAL, -+ .val = 50, -+ .val2 = 0, -+ .time_ns = 20000000, -+ }, -+ { -+ .hw_val = BMC150_BMI323_GYRO_ODR_100_VAL, -+ .val = 100, -+ .val2 = 0, -+ .time_ns = 10000000, -+ }, -+ { -+ .hw_val = BMC150_BMI323_GYRO_ODR_200_VAL, -+ .val = 200, -+ .val2 = 0, -+ .time_ns = 5000000, -+ }, -+ { -+ .hw_val = BMC150_BMI323_GYRO_ODR_400_VAL, -+ .val = 400, -+ .val2 = 0, -+ .time_ns = 2500000, -+ }, -+ { -+ .hw_val = BMC150_BMI323_GYRO_ODR_800_VAL, -+ .val = 800, -+ .val2 = 0, -+ .time_ns = 1250000, -+ }, -+ { -+ .hw_val = BMC150_BMI323_GYRO_ODR_1600_VAL, -+ .val = 1600, -+ .val2 = 0, -+ .time_ns = 625000, -+ }, -+ { -+ .hw_val = BMC150_BMI323_GYRO_ODR_3200_VAL, -+ .val = 3200, -+ .val2 = 0, -+ .time_ns = 312500, -+ }, -+ { -+ .hw_val = BMC150_BMI323_GYRO_ODR_6400_VAL, -+ .val = 6400, -+ .val2 = 0, -+ .time_ns = 156250, -+ }, -+}; -+ -+static const struct bmi323_3db_freq_cutoff_gyro_info { -+ int val; -+ int val2; -+ int ret_type; -+} bmi323_gyro_3db_freq_cutoff[] = { -+ { -+ .val = 0, -+ .val2 = 390615, -+ .ret_type = IIO_VAL_INT_PLUS_MICRO, -+ }, -+ { -+ .val = 0, -+ .val2 = 1953075, // TODO: check if this gets reported correctly... -+ .ret_type = IIO_VAL_INT_PLUS_MICRO, -+ }, -+ { -+ .val = 0, -+ .val2 = 781300, -+ .ret_type = IIO_VAL_INT_PLUS_MICRO, -+ }, -+ { -+ .val = 0, -+ .val2 = 390650, -+ .ret_type = IIO_VAL_INT_PLUS_MICRO, -+ }, -+ { -+ .val = 1, -+ .val2 = 562500, -+ .ret_type = IIO_VAL_INT_PLUS_MICRO, -+ }, -+ { -+ .val = 0, -+ .val2 = 78125, -+ .ret_type = IIO_VAL_INT_PLUS_MICRO, -+ }, -+ { -+ .val = 3, -+ .val2 = 000000, -+ .ret_type = IIO_VAL_INT_PLUS_MICRO, -+ }, -+ { -+ .val = 1, -+ .val2 = 500000, -+ .ret_type = IIO_VAL_INT_PLUS_MICRO, -+ }, -+ { -+ .val = 6, -+ .val2 = 000000, -+ .ret_type = IIO_VAL_INT_PLUS_MICRO, -+ }, -+ { -+ .val = 3, -+ .val2 = 000000, -+ .ret_type = IIO_VAL_INT_PLUS_MICRO, -+ }, -+ { -+ .val = 12, -+ .val2 = 500000, -+ .ret_type = IIO_VAL_INT_PLUS_MICRO, -+ }, -+ { -+ .val = 6, -+ .val2 = 250000, -+ .ret_type = IIO_VAL_INT_PLUS_MICRO, -+ }, -+ { -+ .val = 25, -+ .val2 = 000000, -+ .ret_type = IIO_VAL_INT_PLUS_MICRO, -+ }, -+ { -+ .val = 12, -+ .val2 = 500000, -+ .ret_type = IIO_VAL_INT_PLUS_MICRO, -+ }, -+ { -+ .val = 50, -+ .val2 = 000000, -+ .ret_type = IIO_VAL_INT_PLUS_MICRO, -+ }, -+ { -+ .val = 25, -+ .val2 = 000000, -+ .ret_type = IIO_VAL_INT_PLUS_MICRO, -+ }, -+ { -+ .val = 100, -+ .val2 = 000000, -+ .ret_type = IIO_VAL_INT_PLUS_MICRO, -+ }, -+ { -+ .val = 50, -+ .val2 = 000000, -+ .ret_type = IIO_VAL_INT_PLUS_MICRO, -+ }, -+ { -+ .val = 200, -+ .val2 = 000000, -+ .ret_type = IIO_VAL_INT_PLUS_MICRO, -+ }, -+ { -+ .val = 100, -+ .val2 = 000000, -+ .ret_type = IIO_VAL_INT_PLUS_MICRO, -+ }, -+ { -+ .val = 400, -+ .val2 = 000000, -+ .ret_type = IIO_VAL_INT_PLUS_MICRO, -+ }, -+ { -+ .val = 200, -+ .val2 = 000000, -+ .ret_type = IIO_VAL_INT_PLUS_MICRO, -+ }, -+ { -+ .val = 800, -+ .val2 = 000000, -+ .ret_type = IIO_VAL_INT_PLUS_MICRO, -+ }, -+ { -+ .val = 400, -+ .val2 = 000000, -+ .ret_type = IIO_VAL_INT_PLUS_MICRO, -+ }, -+ { -+ .val = 1600, -+ .val2 = 000000, -+ .ret_type = IIO_VAL_INT_PLUS_MICRO, -+ }, -+ { -+ .val = 800, -+ .val2 = 000000, -+ .ret_type = IIO_VAL_INT_PLUS_MICRO, -+ }, -+ { -+ .val = 1600, -+ .val2 = 000000, -+ .ret_type = IIO_VAL_INT_PLUS_MICRO, -+ }, -+ { -+ .val = 800, -+ .val2 = 000000, -+ .ret_type = IIO_VAL_INT_PLUS_MICRO, -+ }, -+ { -+ .val = 3200, -+ .val2 = 000000, -+ .ret_type = IIO_VAL_INT_PLUS_MICRO, -+ }, -+ { -+ .val = 1600, -+ .val2 = 000000, -+ .ret_type = IIO_VAL_INT_PLUS_MICRO, -+ }, -+}; -+ -+static const int bmi323_accel_scales[] = { -+ 0, 598, 0, 1196, 0, 2392, 0, 4785, -+}; -+ -+static const int bmi323_gyro_scales[] = { -+ 0, 66545, 0, 133090, 0, 266181, 0, 532362, 0, 1064724, -+}; -+ -+static const int bmi323_sample_freqs[] = { -+ 0, 781230, 1, 562600, 3, 125000, 6, 250000, 12, 500000, -+ 25, 0, 50, 0, 100, 0, 200, 0, 400, 0, -+ 800, 0, 1600, 0, 3200, 0, 6400, 0, -+}; -+ -+static const struct { -+ int val; -+ int val2; // IIO_VAL_INT_PLUS_MICRO -+ u8 bw_bits; -+} bmi323_samp_freq_table[] = { { 15, 620000, 0x08 }, { 31, 260000, 0x09 }, -+ { 62, 500000, 0x0A }, { 125, 0, 0x0B }, -+ { 250, 0, 0x0C }, { 500, 0, 0x0D }, -+ { 1000, 0, 0x0E }, { 2000, 0, 0x0F } }; -+ - struct bmc150_accel_chip_info { - const char *name; - u8 chip_id; -@@ -1113,6 +1828,52 @@ static const struct iio_event_spec bmc150_accel_event = { - .num_event_specs = 1 \ - } - -+#define BMI323_ACCEL_CHANNEL(_axis, bits) \ -+ { \ -+ .type = IIO_ACCEL, .modified = 1, .channel2 = IIO_MOD_##_axis, \ -+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ -+ .info_mask_shared_by_type = \ -+ BIT(IIO_CHAN_INFO_SCALE) | \ -+ BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ -+ BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \ -+ .info_mask_shared_by_type_available = \ -+ BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ -+ BIT(IIO_CHAN_INFO_SCALE), \ -+ .scan_index = BMI323_ACCEL_AXIS_##_axis, \ -+ .scan_type = { \ -+ .sign = 's', \ -+ .realbits = (bits), \ -+ .storagebits = 16, \ -+ .shift = 16 - (bits), \ -+ .endianness = IIO_LE, \ -+ }, \ -+ } -+ -+#define BMI323_GYRO_CHANNEL(_axis, bits) \ -+ { \ -+ .type = IIO_ANGL_VEL, .modified = 1, \ -+ .channel2 = IIO_MOD_##_axis, \ -+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ -+ .info_mask_shared_by_type = \ -+ BIT(IIO_CHAN_INFO_SCALE) | \ -+ BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ -+ BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \ -+ .info_mask_shared_by_type_available = \ -+ BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ -+ BIT(IIO_CHAN_INFO_SCALE), \ -+ .scan_index = BMI323_GYRO_AXIS_##_axis, \ -+ .scan_type = { \ -+ .sign = 's', \ -+ .realbits = (bits), \ -+ .storagebits = 16, \ -+ .shift = 16 - (bits), \ -+ .endianness = IIO_LE, \ -+ }, \ -+ /*.ext_info = bmi323_accel_ext_info,*/ \ -+ /*.event_spec = &bmi323_accel_event,*/ \ -+ /*.num_event_specs = 1*/ \ -+ } -+ - #define BMC150_ACCEL_CHANNELS(bits) { \ - { \ - .type = IIO_TEMP, \ -@@ -1595,7 +2356,7 @@ static int bmc150_accel_chip_init(struct bmc150_accel_data *data) - struct device *dev = regmap_get_device(data->regmap); - int ret, i; - unsigned int val; -- -+ - /* - * Reset chip to get it in a known good state. A delay of 1.8ms after - * reset is required according to the data sheets of supported chips. -@@ -1677,6 +2438,11 @@ int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq, - data = iio_priv(indio_dev); - dev_set_drvdata(dev, indio_dev); - -+ /* -+ * Setting the dev_type here is necessary to avoid having it left uninitialized -+ * and therefore potentially executing bmi323 functions for the original bmc150 model. -+ */ -+ data->dev_type = BMC150; - data->regmap = regmap; - data->type = type; - -@@ -1826,12 +2592,1407 @@ void bmc150_accel_core_remove(struct device *dev) - } - EXPORT_SYMBOL_NS_GPL(bmc150_accel_core_remove, IIO_BMC150); - --#ifdef CONFIG_PM_SLEEP --static int bmc150_accel_suspend(struct device *dev) -+struct device *bmi323_get_managed_device(struct bmi323_private_data *bmi323) -+{ -+ if (bmi323->i2c_client != NULL) -+ return &bmi323->i2c_client->dev; -+ -+ return &bmi323->spi_client->dev; -+} -+ -+static int bmi323_set_power_state(struct bmi323_private_data *bmi323, bool on) -+{ -+#ifdef CONFIG_PM -+ struct device *dev = bmi323_get_managed_device(bmi323); -+ int ret; -+ -+ if (on) -+ ret = pm_runtime_get_sync(dev); -+ else { -+ pm_runtime_mark_last_busy(dev); -+ ret = pm_runtime_put_autosuspend(dev); -+ } -+ -+ if (ret < 0) { -+ dev_err(dev, "bmi323_set_power_state failed with %d\n", on); -+ -+ if (on) -+ pm_runtime_put_noidle(dev); -+ -+ return ret; -+ } -+#endif -+ -+ return 0; -+} -+ -+int bmi323_write_u16(struct bmi323_private_data *bmi323, u8 in_reg, -+ u16 in_value) -+{ -+ s32 ret; -+ -+ if (bmi323->i2c_client != NULL) { -+ ret = i2c_smbus_write_i2c_block_data(bmi323->i2c_client, in_reg, -+ sizeof(in_value), -+ (u8 *)(&in_value)); -+ if (ret != 0) { -+ return -2; -+ } -+ -+ return 0; -+ } else if (bmi323->spi_client != NULL) { -+ /* -+ * To whoever may need this: implementing this should be straightforward: -+ * it's specular to the i2c part. -+ */ -+ -+ return -EINVAL; // TODO: change with 0 once implemented -+ } -+ -+ return -EINVAL; -+} -+EXPORT_SYMBOL_NS_GPL(bmi323_write_u16, IIO_BMC150); -+ -+int bmi323_read_u16(struct bmi323_private_data *bmi323, u8 in_reg, -+ u16 *out_value) -+{ -+ s32 ret; -+ u8 read_bytes[4]; -+ -+ if (bmi323->i2c_client != NULL) { -+ ret = i2c_smbus_read_i2c_block_data(bmi323->i2c_client, in_reg, -+ sizeof(read_bytes), -+ &read_bytes[0]); -+ if (ret != 4) { -+ return ret; -+ } -+ -+ // DUMMY = read_bytes[0] -+ // DUMMY = read_bytes[1] -+ // LSB = read_bytes[2] -+ // MSB = read_bytes[3] -+ u8 *o = (u8 *)out_value; -+ o[0] = read_bytes[2]; -+ o[1] = read_bytes[3]; -+ -+ return 0; -+ } else if (bmi323->spi_client != NULL) { -+ printk(KERN_CRIT -+ "bmi323: SPI interface is not yet implemented.\n"); -+ -+ /* -+ * To whoever may need this: implementing this should be straightforward: -+ * it's specular to the i2c part except that the dummy data is just 1 byte. -+ */ -+ -+ return -EINVAL; // TODO: change with 0 once implemented -+ } -+ -+ return -EINVAL; -+} -+EXPORT_SYMBOL_NS_GPL(bmi323_read_u16, IIO_BMC150); -+ -+int bmi323_chip_check(struct bmi323_private_data *bmi323) -+{ -+ u16 chip_id; -+ int ret; -+ -+ ret = bmi323_read_u16(bmi323, BMC150_BMI323_CHIP_ID_REG, &chip_id); -+ if (ret != 0) { -+ return ret; -+ } -+ -+ if (((chip_id)&0x00FF) != cpu_to_le16((u16)0x0043U)) { -+ dev_err(bmi323->dev, -+ "bmi323_chip_check failed with: %d; chip_id = 0x%04x", -+ ret, chip_id); -+ -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+EXPORT_SYMBOL_NS_GPL(bmi323_chip_check, IIO_BMC150); -+ -+static int bmi323_buffer_preenable(struct iio_dev *indio_dev) -+{ -+ struct bmc150_accel_data *data = iio_priv(indio_dev); -+ -+ const int ret = bmi323_set_power_state(&data->bmi323, true); -+ -+ if (ret == 0) { -+ mutex_lock(&data->bmi323.mutex); -+ data->bmi323.fifo_frame_time_diff_ns = -+ (data->bmi323.acc_odr_time_ns >= -+ data->bmi323.gyr_odr_time_ns) ? -+ data->bmi323.acc_odr_time_ns : -+ data->bmi323.gyr_odr_time_ns; -+ mutex_unlock(&data->bmi323.mutex); -+ } -+ -+ return ret; -+} -+ -+static int bmi323_buffer_postenable(struct iio_dev *indio_dev) -+{ -+ //struct bmc150_accel_data *data = iio_priv(indio_dev); -+ -+ /* -+ * This code is a placeholder until I can get a way to test it -+ */ -+ -+ return 0; -+} -+ -+static int bmi323_buffer_predisable(struct iio_dev *indio_dev) -+{ -+ //struct bmc150_accel_data *data = iio_priv(indio_dev); -+ -+ /* -+ * This code is a placeholder until I can get a way to test it -+ */ -+ -+ return 0; -+} -+ -+static int bmi323_buffer_postdisable(struct iio_dev *indio_dev) -+{ -+ struct bmc150_accel_data *data = iio_priv(indio_dev); -+ -+ return bmi323_set_power_state(&data->bmi323, true); -+} -+ -+static const struct iio_buffer_setup_ops bmi323_buffer_ops = { -+ .preenable = bmi323_buffer_preenable, -+ .postenable = bmi323_buffer_postenable, -+ .predisable = bmi323_buffer_predisable, -+ .postdisable = bmi323_buffer_postdisable, -+}; -+ -+int bmi323_chip_rst(struct bmi323_private_data *bmi323) -+{ -+ u16 sensor_status = 0x0000, device_status = 0x0000; -+ int ret; -+ -+ ret = bmi323_write_u16(bmi323, BMC150_BMI323_SOFT_RESET_REG, -+ cpu_to_le16((u16)BMC150_BMI323_SOFT_RESET_VAL)); -+ if (ret != 0) { -+ dev_err(bmi323->dev, -+ "bmi323: error while issuing the soft-reset command: %d", -+ ret); -+ return ret; -+ } -+ -+ /* wait the specified amount of time... I agree with the bmc150 module: better safe than sorry. */ -+ msleep(5); -+ -+ // if the device is connected over SPI a dummy read is to be performed once after each reset -+ if (bmi323->spi_client != NULL) { -+ dev_info(bmi323->dev, -+ "issuing the dummy read to switch mode to SPI"); -+ -+ // do not even check the result of that... it's just a dummy read -+ bmi323_chip_check(bmi323); -+ } -+ -+ ret = bmi323_chip_check(bmi323); -+ if (ret != 0) { -+ return ret; -+ } -+ -+ /* now check the correct initialization status as per datasheet */ -+ ret = bmi323_read_u16(bmi323, 0x01, &device_status); -+ if (ret != 0) { -+ return -EINVAL; -+ } -+ -+ if ((device_status & cpu_to_le16((u16)0x00FFU)) != -+ cpu_to_le16((u16)0x0000U)) { -+ dev_err(bmi323->dev, -+ "bmi323: device_status incorrect: %d; device_status = 0x%04x", -+ ret, device_status); -+ -+ /* from the datasheet: power error */ -+ return -EINVAL; -+ } -+ -+ /* from the datasheet: power ok */ -+ ret = bmi323_read_u16(bmi323, 0x02, &sensor_status); -+ if (ret != 0) { -+ return -EINVAL; -+ } -+ -+ if ((sensor_status & cpu_to_le16((u16)0x00FFU)) != -+ cpu_to_le16((u16)0x0001U)) { -+ dev_err(bmi323->dev, -+ "bmi323: sensor_status incorrect: %d; sensor_status = 0x%04x", -+ ret, sensor_status); -+ -+ /* from the datasheet: initialization error */ -+ return -EINVAL; -+ } -+ -+ /* from the datasheet: initialization ok */ -+ return 0; -+} -+EXPORT_SYMBOL_NS_GPL(bmi323_chip_rst, IIO_BMC150); -+ -+static const struct iio_chan_spec bmi323_channels[] = { -+ BMI323_ACCEL_CHANNEL(X, 16), -+ BMI323_ACCEL_CHANNEL(Y, 16), -+ BMI323_ACCEL_CHANNEL(Z, 16), -+ BMI323_GYRO_CHANNEL(X, 16), -+ BMI323_GYRO_CHANNEL(Y, 16), -+ BMI323_GYRO_CHANNEL(Z, 16), -+ { -+ .type = IIO_TEMP, -+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | -+ BIT(IIO_CHAN_INFO_SCALE) | -+ BIT(IIO_CHAN_INFO_OFFSET), -+ .scan_index = BMI323_TEMP, -+ }, -+ IIO_CHAN_SOFT_TIMESTAMP(BMI323_AXIS_MAX), -+}; -+ -+static int bmi323_read_raw(struct iio_dev *indio_dev, -+ struct iio_chan_spec const *chan, int *val, -+ int *val2, long mask) -+{ -+ struct bmc150_accel_data *data = iio_priv(indio_dev); -+ int ret = -EINVAL, was_sleep_modified = -1; -+ u16 raw_read = 0x8000; -+ -+ mutex_lock(&data->bmi323.mutex); -+ -+ if ((data->bmi323.flags & BMI323_FLAGS_RESET_FAILED) != 0x00U) { -+ dev_err(data->bmi323.dev, -+ "bmi323 error: device has not being woken up correctly."); -+ mutex_unlock(&data->bmi323.mutex); -+ return -EBUSY; -+ } -+ -+ switch (mask) { -+ case IIO_CHAN_INFO_RAW: { -+ switch (chan->type) { -+ case IIO_TEMP: -+ if (iio_buffer_enabled(indio_dev)) { -+ ret = -EBUSY; -+ goto bmi323_read_raw_error; -+ } -+ -+ was_sleep_modified = -+ bmi323_set_power_state(&data->bmi323, true); -+ if (was_sleep_modified != 0) { -+ ret = was_sleep_modified; -+ goto bmi323_read_raw_error_power; -+ } -+ -+ ret = iio_device_claim_direct_mode(indio_dev); -+ if (ret != 0) { -+ printk(KERN_CRIT -+ "bmc150 bmi323_read_raw IIO_TEMP iio_device_claim_direct_mode returned %d\n", -+ ret); -+ goto bmi323_read_raw_error; -+ } -+ -+ ret = bmi323_read_u16( -+ &data->bmi323, -+ BMC150_BMI323_TEMPERATURE_DATA_REG, &raw_read); -+ iio_device_release_direct_mode(indio_dev); -+ if (ret != 0) { -+ printk(KERN_CRIT -+ "bmc150 bmi323_read_raw IIO_TEMP bmi323_read_u16 returned %d\n", -+ ret); -+ goto bmi323_read_raw_error; -+ } -+ -+ *val = sign_extend32(le16_to_cpu(raw_read), 15); -+ bmi323_set_power_state(&data->bmi323, false); -+ mutex_unlock(&data->bmi323.mutex); -+ return IIO_VAL_INT; -+ -+ case IIO_ACCEL: -+ if (iio_buffer_enabled(indio_dev)) { -+ ret = -EBUSY; -+ goto bmi323_read_raw_error; -+ } -+ -+ was_sleep_modified = -+ bmi323_set_power_state(&data->bmi323, true); -+ if (was_sleep_modified != 0) { -+ ret = was_sleep_modified; -+ goto bmi323_read_raw_error_power; -+ } -+ -+ ret = iio_device_claim_direct_mode(indio_dev); -+ if (ret != 0) { -+ printk(KERN_CRIT -+ "bmc150 bmi323_read_raw IIO_ACCEL iio_device_claim_direct_mode returned %d\n", -+ ret); -+ goto bmi323_read_raw_error; -+ } -+ -+ ret = bmi323_read_u16(&data->bmi323, -+ BMC150_BMI323_DATA_BASE_REG + -+ (u8)(chan->scan_index), -+ &raw_read); -+ iio_device_release_direct_mode(indio_dev); -+ if (ret != 0) { -+ printk(KERN_CRIT -+ "bmc150 bmi323_read_raw IIO_ACCEL bmi323_read_u16 returned %d\n", -+ ret); -+ goto bmi323_read_raw_error; -+ } -+ *val = sign_extend32(le16_to_cpu(raw_read), 15); -+ bmi323_set_power_state(&data->bmi323, false); -+ mutex_unlock(&data->bmi323.mutex); -+ return IIO_VAL_INT; -+ -+ case IIO_ANGL_VEL: -+ if (iio_buffer_enabled(indio_dev)) { -+ ret = -EBUSY; -+ goto bmi323_read_raw_error; -+ } -+ -+ was_sleep_modified = -+ bmi323_set_power_state(&data->bmi323, true); -+ if (was_sleep_modified != 0) { -+ ret = was_sleep_modified; -+ goto bmi323_read_raw_error_power; -+ } -+ -+ ret = iio_device_claim_direct_mode(indio_dev); -+ if (ret != 0) { -+ printk(KERN_CRIT -+ "bmc150 bmi323_read_raw IIO_ANGL_VEL iio_device_claim_direct_mode returned %d\n", -+ ret); -+ goto bmi323_read_raw_error; -+ } -+ -+ ret = bmi323_read_u16(&data->bmi323, -+ BMC150_BMI323_DATA_BASE_REG + -+ (u8)(chan->scan_index), -+ &raw_read); -+ iio_device_release_direct_mode(indio_dev); -+ if (ret != 0) { -+ printk(KERN_CRIT -+ "bmc150 bmi323_read_raw IIO_ANGL_VEL bmi323_read_u16 returned %d\n", -+ ret); -+ goto bmi323_read_raw_error; -+ } -+ -+ *val = sign_extend32(le16_to_cpu(raw_read), 15); -+ bmi323_set_power_state(&data->bmi323, false); -+ mutex_unlock(&data->bmi323.mutex); -+ return IIO_VAL_INT; -+ -+ default: -+ goto bmi323_read_raw_error; -+ } -+ } -+ case IIO_CHAN_INFO_OFFSET: { -+ switch (chan->type) { -+ case IIO_TEMP: -+ *val = BMC150_BMI323_TEMPER_CENTER_VAL; -+ *val2 = 0; -+ mutex_unlock(&data->bmi323.mutex); -+ return IIO_VAL_INT; -+ -+ default: -+ ret = -EINVAL; -+ goto bmi323_read_raw_error; -+ } -+ } -+ case IIO_CHAN_INFO_SCALE: -+ switch (chan->type) { -+ case IIO_TEMP: { -+ *val = 0; -+ *val2 = BMC150_BMI323_TEMPER_LSB_PER_KELVIN_VAL; -+ mutex_unlock(&data->bmi323.mutex); -+ return IIO_VAL_FRACTIONAL; -+ } -+ case IIO_ACCEL: { -+ u8 *le_raw_read = -+ (u8 *)&data->bmi323.acc_conf_reg_value; -+ for (int s = 0; s < ARRAY_SIZE(bmi323_accel_scale_map); -+ ++s) { -+ if (((le_raw_read[0]) & ((u16)0b01110000U)) == -+ (bmi323_accel_scale_map[s].hw_val)) { -+ *val = bmi323_accel_scale_map[s].val; -+ *val2 = bmi323_accel_scale_map[s].val2; -+ -+ mutex_unlock(&data->bmi323.mutex); -+ return bmi323_accel_scale_map[s] -+ .ret_type; -+ } -+ } -+ -+ ret = -EINVAL; -+ goto bmi323_read_raw_error; -+ } -+ case IIO_ANGL_VEL: { -+ u8 *le_raw_read = -+ (u8 *)&data->bmi323.gyr_conf_reg_value; -+ for (int s = 0; s < ARRAY_SIZE(bmi323_gyro_scale_map); -+ ++s) { -+ if (((le_raw_read[0]) & ((u16)0b01110000U)) == -+ (bmi323_gyro_scale_map[s].hw_val)) { -+ *val = bmi323_gyro_scale_map[s].val; -+ *val2 = bmi323_gyro_scale_map[s].val2; -+ -+ mutex_unlock(&data->bmi323.mutex); -+ return bmi323_gyro_scale_map[s].ret_type; -+ } -+ } -+ -+ ret = -EINVAL; -+ goto bmi323_read_raw_error; -+ } -+ default: -+ ret = -EINVAL; -+ goto bmi323_read_raw_error; -+ } -+ case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: -+ switch (chan->type) { -+ case IIO_ACCEL: { -+ u8 *le_raw_read = -+ (u8 *)&data->bmi323.acc_conf_reg_value; -+ for (int s = 0; s < ARRAY_SIZE(bmi323_accel_odr_map); -+ ++s) { -+ if (((le_raw_read[0]) & ((u16)0x0FU)) == -+ (bmi323_accel_odr_map[s].hw_val)) { -+ /* -+ * from tha datasheed: -3dB cut-off frequency can be configured with the bit 7 of GYR_confm, -+ * also called acc_bw that can either be 0 or 1, where 1 means odr/4 and 0 means odr/2 -+ */ -+ int freq_adj_idx = -+ (((le_raw_read[0]) & -+ ((u8)0x80U)) == (u8)0x00U) ? -+ (s * 2) + 0 : -+ (s * 2) + 1; -+ *val = bmi323_accel_3db_freq_cutoff -+ [freq_adj_idx] -+ .val; -+ *val2 = bmi323_accel_3db_freq_cutoff -+ [freq_adj_idx] -+ .val2; -+ -+ mutex_unlock(&data->bmi323.mutex); -+ return IIO_VAL_INT_PLUS_MICRO; -+ } -+ } -+ -+ ret = -EINVAL; -+ goto bmi323_read_raw_error; -+ } -+ case IIO_ANGL_VEL: { -+ u8 *le_raw_read = -+ (u8 *)&data->bmi323.gyr_conf_reg_value; -+ for (int s = 0; s < ARRAY_SIZE(bmi323_gyro_odr_map); -+ ++s) { -+ if (((le_raw_read[0]) & ((u16)0x0FU)) == -+ (bmi323_gyro_odr_map[s].hw_val)) { -+ /* -+ * from tha datasheed: -3dB cut-off frequency can be configured with the bit 7 of GYR_confm, -+ * also called acc_bw that can either be 0 or 1, where 1 means odr/4 and 0 means odr/2 -+ */ -+ int freq_adj_idx = -+ (((le_raw_read[0]) & -+ ((u8)0x80U)) == (u8)0x0000U) ? -+ (s * 2) + 0 : -+ (s * 2) + 1; -+ *val = bmi323_gyro_3db_freq_cutoff -+ [freq_adj_idx] -+ .val; -+ *val2 = bmi323_gyro_3db_freq_cutoff -+ [freq_adj_idx] -+ .val2; -+ -+ mutex_unlock(&data->bmi323.mutex); -+ return bmi323_gyro_3db_freq_cutoff -+ [freq_adj_idx] -+ .ret_type; -+ } -+ } -+ -+ ret = -EINVAL; -+ goto bmi323_read_raw_error; -+ } -+ default: { -+ ret = -EINVAL; -+ goto bmi323_read_raw_error; -+ } -+ } -+ case IIO_CHAN_INFO_SAMP_FREQ: -+ switch (chan->type) { -+ case IIO_TEMP: { -+ -+ // while in normal or power mode the temperature sensur has a 50Hz sampling frequency -+ *val = 50; -+ *val2 = 0; -+ -+ mutex_unlock(&data->bmi323.mutex); -+ return IIO_VAL_INT_PLUS_MICRO; -+ } -+ case IIO_ACCEL: { -+ u8 *le_raw_read = -+ (u8 *)&data->bmi323.acc_conf_reg_value; -+ for (int s = 0; s < ARRAY_SIZE(bmi323_accel_odr_map); -+ ++s) { -+ if (((le_raw_read[0]) & ((u16)0x0FU)) == -+ (bmi323_accel_odr_map[s].hw_val)) { -+ *val = bmi323_accel_odr_map[s].val; -+ *val2 = bmi323_accel_odr_map[s].val2; -+ -+ mutex_unlock(&data->bmi323.mutex); -+ return IIO_VAL_INT_PLUS_MICRO; -+ } -+ } -+ -+ ret = -EINVAL; -+ goto bmi323_read_raw_error; -+ } -+ case IIO_ANGL_VEL: { -+ u8 *le_raw_read = -+ (u8 *)&data->bmi323.gyr_conf_reg_value; -+ for (int s = 0; s < ARRAY_SIZE(bmi323_gyro_odr_map); -+ ++s) { -+ if (((le_raw_read[0]) & ((u16)0x0FU)) == -+ (bmi323_gyro_odr_map[s].hw_val)) { -+ *val = bmi323_gyro_odr_map[s].val; -+ *val2 = bmi323_gyro_odr_map[s].val2; -+ -+ mutex_unlock(&data->bmi323.mutex); -+ return IIO_VAL_INT_PLUS_MICRO; -+ } -+ } -+ -+ ret = -EINVAL; -+ goto bmi323_read_raw_error; -+ } -+ default: -+ ret = -EINVAL; -+ goto bmi323_read_raw_error; -+ } -+ default: -+ ret = -EINVAL; -+ goto bmi323_read_raw_error; -+ } -+ -+bmi323_read_raw_error: -+ if (was_sleep_modified == 0) { -+ bmi323_set_power_state(&data->bmi323, false); -+ } -+ -+bmi323_read_raw_error_power: -+ mutex_unlock(&data->bmi323.mutex); -+ return ret; -+} -+ -+static int bmi323_write_raw(struct iio_dev *indio_dev, -+ struct iio_chan_spec const *chan, int val, int val2, -+ long mask) -+{ -+ struct bmc150_accel_data *data = iio_priv(indio_dev); -+ int ret = -EINVAL, was_sleep_modified = -1; -+ -+ mutex_lock(&data->bmi323.mutex); -+ -+ if ((data->bmi323.flags & BMI323_FLAGS_RESET_FAILED) != 0x00U) { -+ dev_err(data->bmi323.dev, -+ "bmi323 error: device has not being woken up correctly."); -+ mutex_unlock(&data->bmi323.mutex); -+ return -EBUSY; -+ } -+ -+ switch (mask) { -+ case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: -+ switch (chan->type) { -+ default: { -+ ret = -EINVAL; -+ goto bmi323_write_raw_error; -+ } -+ } -+ case IIO_CHAN_INFO_SAMP_FREQ: -+ switch (chan->type) { -+ case IIO_ACCEL: -+ if (iio_buffer_enabled(indio_dev)) { -+ ret = -EBUSY; -+ goto bmi323_write_raw_error; -+ } -+ -+ for (int s = 0; s < ARRAY_SIZE(bmi323_accel_odr_map); -+ ++s) { -+ if ((bmi323_accel_odr_map[s].val == val) && -+ (bmi323_accel_odr_map[s].val2 == val2)) { -+ const u16 conf_backup = -+ data->bmi323.acc_conf_reg_value; -+ u8 *le_raw_read = -+ (u8 *)&data->bmi323 -+ .acc_conf_reg_value; -+ le_raw_read[0] &= (u8)0b11110000U; -+ le_raw_read[0] |= -+ ((u8)bmi323_gyro_odr_map[s] -+ .hw_val); -+ -+ was_sleep_modified = -+ bmi323_set_power_state( -+ &data->bmi323, true); -+ if (was_sleep_modified != 0) { -+ ret = was_sleep_modified; -+ data->bmi323.acc_conf_reg_value = -+ conf_backup; -+ goto bmi323_write_raw_error_power; -+ } -+ -+ ret = bmi323_write_u16( -+ &data->bmi323, -+ BMC150_BMI323_ACC_CONF_REG, -+ data->bmi323.acc_conf_reg_value); -+ if (ret != 0) { -+ data->bmi323.acc_conf_reg_value = -+ conf_backup; -+ goto bmi323_write_raw_error; -+ } -+ -+ data->bmi323.acc_odr_time_ns = -+ bmi323_accel_odr_map[s].time_ns; -+ bmi323_set_power_state(&data->bmi323, -+ false); -+ mutex_unlock(&data->bmi323.mutex); -+ return 0; -+ } -+ } -+ -+ ret = -EINVAL; -+ goto bmi323_write_raw_error; -+ case IIO_ANGL_VEL: -+ if (iio_buffer_enabled(indio_dev)) { -+ ret = -EBUSY; -+ goto bmi323_write_raw_error; -+ } -+ -+ for (int s = 0; s < ARRAY_SIZE(bmi323_gyro_odr_map); -+ ++s) { -+ if ((bmi323_gyro_odr_map[s].val == val) && -+ (bmi323_gyro_odr_map[s].val2 == val2)) { -+ const u16 conf_backup = -+ data->bmi323.gyr_conf_reg_value; -+ u8 *le_raw_read = -+ (u8 *)&data->bmi323 -+ .gyr_conf_reg_value; -+ le_raw_read[0] &= (u8)0b11110000U; -+ le_raw_read[0] |= -+ ((u8)bmi323_gyro_odr_map[s] -+ .hw_val); -+ -+ was_sleep_modified = -+ bmi323_set_power_state( -+ &data->bmi323, true); -+ if (was_sleep_modified != 0) { -+ ret = was_sleep_modified; -+ data->bmi323.gyr_conf_reg_value = -+ conf_backup; -+ goto bmi323_write_raw_error_power; -+ } -+ -+ ret = bmi323_write_u16( -+ &data->bmi323, -+ BMC150_BMI323_GYR_CONF_REG, -+ data->bmi323.gyr_conf_reg_value); -+ if (ret != 0) { -+ data->bmi323.gyr_conf_reg_value = -+ conf_backup; -+ goto bmi323_write_raw_error; -+ } -+ -+ data->bmi323.gyr_odr_time_ns = -+ bmi323_gyro_odr_map[s].time_ns; -+ bmi323_set_power_state(&data->bmi323, -+ false); -+ mutex_unlock(&data->bmi323.mutex); -+ return 0; -+ } -+ } -+ -+ ret = -EINVAL; -+ goto bmi323_write_raw_error; -+ -+ /* Termometer also ends up here: its sampling frequency depends on the chip configuration and cannot be changed */ -+ default: -+ ret = -EINVAL; -+ goto bmi323_write_raw_error; -+ } -+ -+ break; -+ case IIO_CHAN_INFO_SCALE: -+ switch (chan->type) { -+ case IIO_ACCEL: -+ if (iio_buffer_enabled(indio_dev)) { -+ ret = -EBUSY; -+ goto bmi323_write_raw_error; -+ } -+ -+ for (int s = 0; s < ARRAY_SIZE(bmi323_accel_scale_map); -+ ++s) { -+ if ((bmi323_accel_scale_map[s].val == val) && -+ (bmi323_accel_scale_map[s].val2 == val2)) { -+ u8 *le_raw_read = -+ (u8 *)&data->bmi323 -+ .acc_conf_reg_value; -+ le_raw_read[0] &= (u8)0b10001111U; -+ le_raw_read[0] |= -+ ((u8)bmi323_accel_scale_map[s] -+ .hw_val); -+ -+ was_sleep_modified = -+ bmi323_set_power_state( -+ &data->bmi323, true); -+ if (was_sleep_modified != 0) { -+ ret = was_sleep_modified; -+ goto bmi323_write_raw_error_power; -+ } -+ -+ ret = bmi323_write_u16( -+ &data->bmi323, -+ BMC150_BMI323_ACC_CONF_REG, -+ data->bmi323.acc_conf_reg_value); -+ if (ret != 0) { -+ goto bmi323_write_raw_error; -+ } -+ -+ bmi323_set_power_state(&data->bmi323, -+ false); -+ mutex_unlock(&data->bmi323.mutex); -+ return 0; -+ } -+ } -+ -+ dev_warn( -+ data->bmi323.dev, -+ "bmi323 error: accel scale val=%d,val2=%d unavailable: ignoring.", -+ val, val2); -+ -+ ret = -EINVAL; -+ goto bmi323_write_raw_error; -+ case IIO_ANGL_VEL: -+ if (iio_buffer_enabled(indio_dev)) { -+ ret = -EBUSY; -+ goto bmi323_write_raw_error; -+ } -+ -+ for (int s = 0; s < ARRAY_SIZE(bmi323_gyro_scale_map); -+ ++s) { -+ if ((bmi323_gyro_scale_map[s].val == val) && -+ (bmi323_gyro_scale_map[s].val2 == val2)) { -+ u8 *le_raw_read = -+ (u8 *)&data->bmi323 -+ .gyr_conf_reg_value; -+ le_raw_read[0] &= (u8)0b10001111U; -+ le_raw_read[0] |= -+ ((u8)bmi323_gyro_scale_map[s] -+ .hw_val); -+ -+ was_sleep_modified = -+ bmi323_set_power_state( -+ &data->bmi323, true); -+ if (was_sleep_modified != 0) { -+ ret = was_sleep_modified; -+ goto bmi323_write_raw_error_power; -+ } -+ -+ ret = bmi323_write_u16( -+ &data->bmi323, -+ BMC150_BMI323_GYR_CONF_REG, -+ data->bmi323.acc_conf_reg_value); -+ if (ret != 0) { -+ goto bmi323_write_raw_error; -+ } -+ -+ bmi323_set_power_state(&data->bmi323, -+ false); -+ mutex_unlock(&data->bmi323.mutex); -+ return 0; -+ } -+ } -+ -+ dev_warn( -+ data->bmi323.dev, -+ "bmi323 error: gyro scale val=%d,val2=%d unavailable: ignoring.", -+ val, val2); -+ -+ ret = -EINVAL; -+ goto bmi323_write_raw_error; -+ -+ default: -+ ret = -EINVAL; -+ goto bmi323_write_raw_error; -+ } -+ -+ default: -+ ret = -EINVAL; -+ goto bmi323_write_raw_error; -+ } -+ -+bmi323_write_raw_error: -+ if (was_sleep_modified == 0) { -+ bmi323_set_power_state(&data->bmi323, false); -+ } -+ -+bmi323_write_raw_error_power: -+ mutex_unlock(&data->bmi323.mutex); -+ return ret; -+} -+ -+static int bmi323_read_avail(struct iio_dev *indio_dev, -+ struct iio_chan_spec const *chan, const int **vals, -+ int *type, int *length, long mask) -+{ -+ switch (mask) { -+ case IIO_CHAN_INFO_SCALE: -+ switch (chan->type) { -+ case IIO_ACCEL: -+ *type = IIO_VAL_INT_PLUS_MICRO; -+ *vals = bmi323_accel_scales; -+ *length = ARRAY_SIZE(bmi323_accel_scales); -+ return IIO_AVAIL_LIST; -+ case IIO_ANGL_VEL: -+ *type = IIO_VAL_INT_PLUS_NANO; -+ *vals = bmi323_gyro_scales; -+ *length = ARRAY_SIZE(bmi323_gyro_scales); -+ return IIO_AVAIL_LIST; -+ default: -+ return -EINVAL; -+ } -+ case IIO_CHAN_INFO_SAMP_FREQ: -+ *type = IIO_VAL_INT_PLUS_MICRO; -+ *vals = bmi323_sample_freqs; -+ *length = ARRAY_SIZE(bmi323_sample_freqs); -+ return IIO_AVAIL_LIST; -+ default: -+ return -EINVAL; -+ } -+} -+ -+static const struct iio_info bmi323_accel_info = { -+ .read_raw = bmi323_read_raw, -+ .write_raw = bmi323_write_raw, -+ .read_avail = bmi323_read_avail, -+ //.hwfifo_flush_to_buffer = bmi323_fifo_flush, -+}; -+ -+static int bmi323_fifo_flush(struct iio_dev *indio_dev) -+{ -+ struct bmc150_accel_data *data = iio_priv(indio_dev); -+ int ret; -+ -+ ret = bmi323_write_u16(&data->bmi323, 0x37, cpu_to_le16(0x01)); -+ -+ return ret; -+} -+ -+static const u16 stub_value = 0x8000; -+ -+#define ADVANCE_AT_REQ_OR_AVAIL(req, avail, dst, dst_offset, src, src_offset) \ -+ if (req) { \ -+ if (gyr_avail) { \ -+ memcpy((void *)(dst + dst_offset), \ -+ (const void *)(src + src_offset), 2); \ -+ src_offset += 2; \ -+ } else { \ -+ memcpy((void *)(dst + dst_offset), \ -+ (const void *)((const u8 *)(&stub_value)), 2); \ -+ } \ -+ dst_offset += 2; \ -+ } else { \ -+ if (avail) { \ -+ src_offset += 2; \ -+ } \ -+ } -+ -+static irqreturn_t iio_bmi323_trigger_h(int irq, void *p) -+{ -+ printk(KERN_WARNING "bmi323 executed iio_bmi323_trigger_h"); -+ -+ struct iio_poll_func *pf = p; -+ struct iio_dev *indio_dev = pf->indio_dev; -+ struct bmc150_accel_data *indio_data = iio_priv(indio_dev); -+ -+ mutex_lock(&indio_data->bmi323.mutex); -+ -+ const bool temp_avail = ((indio_data->bmi323.fifo_conf_reg_value & -+ (cpu_to_le16(0b0000100000000000))) != 0); -+ const bool gyr_avail = ((indio_data->bmi323.fifo_conf_reg_value & -+ (cpu_to_le16(0b0000010000000000))) != 0); -+ const bool acc_avail = ((indio_data->bmi323.fifo_conf_reg_value & -+ (cpu_to_le16(0b0000001000000000))) != 0); -+ const bool time_avail = ((indio_data->bmi323.fifo_conf_reg_value & -+ (cpu_to_le16(0b0000000100000000))) != 0); -+ -+ /* Calculate the number of bytes for a frame */ -+ const u16 frames_aggregate_size_in_words = -+ /* 2 * */ ((temp_avail ? 1 : 0) + (gyr_avail ? 3 : 0) + -+ (acc_avail ? 3 : 0) + (time_avail ? 1 : 0)); -+ -+ u16 available_words = 0; -+ const int available_words_read_res = bmi323_read_u16( -+ &indio_data->bmi323, BMC150_BMI323_FIFO_FILL_LEVEL_REG, -+ &available_words); -+ if (available_words_read_res != 0) { -+ goto bmi323_irq_done; -+ } -+ -+ const u16 available_frame_aggregates = (le16_to_cpu(available_words)) / -+ (frames_aggregate_size_in_words); -+ -+ const s64 current_timestamp_ns = iio_get_time_ns(indio_dev); -+ const s64 fifo_frame_time_ns = -+ indio_data->bmi323.fifo_frame_time_diff_ns; -+ const s64 first_sample_timestamp_ns = -+ current_timestamp_ns - -+ (fifo_frame_time_ns * (s64)(available_frame_aggregates)); -+ -+ /* This can hold one full block */ -+ u8 temp_data[16]; -+ -+ /* This is fifo data as read from the sensor */ -+ u8 fifo_data[32]; -+ -+ /* -+ | CHANNEL | scan_index -+ |============================ -+ | | | -+ | ACCEL_X | 0 | -+ | ACCEL_Y | 1 | -+ | ACCEL_Y | 2 | -+ | GYRO_X | 3 | -+ | GYRO_Y | 4 | -+ | GYRO_Z | 5 | -+ | TEMP | 6 | -+ | TIMESTAMP | ? | -+ */ -+ bool accel_x_requested = false; -+ bool accel_y_requested = false; -+ bool accel_z_requested = false; -+ bool gyro_x_requested = false; -+ bool gyro_y_requested = false; -+ bool gyro_z_requested = false; -+ bool temp_requested = false; -+ -+ int j = 0; -+ for_each_set_bit(j, indio_dev->active_scan_mask, -+ indio_dev->masklength) { -+ switch (j) { -+ case 0: -+ accel_x_requested = true; -+ break; -+ case 1: -+ accel_y_requested = true; -+ break; -+ case 2: -+ accel_z_requested = true; -+ break; -+ case 3: -+ gyro_x_requested = true; -+ break; -+ case 4: -+ gyro_y_requested = true; -+ break; -+ case 5: -+ gyro_z_requested = true; -+ break; -+ case 6: -+ temp_requested = true; -+ break; -+ default: -+ break; -+ } -+ } -+ -+ u16 current_fifo_buffer_offset_bytes = 0; -+ for (u16 f = 0; f < available_frame_aggregates; ++f) { -+ u16 current_sample_buffer_offset = 0; -+ -+ /* Read data from the raw device */ -+ if (indio_data->bmi323.i2c_client != NULL) { -+ const int bytes_to_read = -+ 2 + (2 * frames_aggregate_size_in_words); -+ int read_block_ret = i2c_smbus_read_i2c_block_data( -+ indio_data->bmi323.i2c_client, -+ BMC150_BMI323_FIFO_DATA_REG, bytes_to_read, -+ &fifo_data[0]); -+ if (read_block_ret < bytes_to_read) { -+ dev_warn( -+ &indio_data->bmi323.i2c_client->dev, -+ "bmi323: i2c_smbus_read_i2c_block_data wrong return: expected %d bytes, %d arrived. Doing what is possible with recovered data.\n", -+ bytes_to_read, read_block_ret); -+ -+ /* at this point FIFO buffer must be flushed to avoid interpreting data incorrectly the next trigger */ -+ const int flush_res = -+ bmi323_fifo_flush(indio_dev); -+ if (flush_res != 0) { -+ dev_err(&indio_data->bmi323.i2c_client -+ ->dev, -+ "bmi323: Could not flush FIFO (%d). Following buffer data might be corrupted.\n", -+ flush_res); -+ } -+ -+ goto bmi323_irq_done; -+ } -+ -+ /* Discard 2-bytes dummy data from I2C */ -+ current_fifo_buffer_offset_bytes = 2; -+ } else if (indio_data->bmi323.spi_client != NULL) { -+ printk(KERN_CRIT -+ "bmi323: SPI interface is not yet implemented.\n"); -+ -+ /* -+ * To whoever may need this: implementing this should be straightforward: -+ * it's specular to the i2c part. -+ */ -+ -+ /* Discard 1-byte dummy data from SPI */ -+ current_fifo_buffer_offset_bytes = 1; -+ -+ goto bmi323_irq_done; -+ } -+ -+ ADVANCE_AT_REQ_OR_AVAIL(accel_x_requested, acc_avail, -+ (u8 *)&temp_data[0], -+ current_sample_buffer_offset, -+ (u8 *)&fifo_data[0], -+ current_fifo_buffer_offset_bytes); -+ ADVANCE_AT_REQ_OR_AVAIL(accel_y_requested, acc_avail, -+ (u8 *)&temp_data[0], -+ current_sample_buffer_offset, -+ (u8 *)&fifo_data[0], -+ current_fifo_buffer_offset_bytes); -+ ADVANCE_AT_REQ_OR_AVAIL(accel_z_requested, acc_avail, -+ (u8 *)&temp_data[0], -+ current_sample_buffer_offset, -+ (u8 *)&fifo_data[0], -+ current_fifo_buffer_offset_bytes); -+ ADVANCE_AT_REQ_OR_AVAIL(gyro_x_requested, gyr_avail, -+ (u8 *)&temp_data[0], -+ current_sample_buffer_offset, -+ (u8 *)&fifo_data[0], -+ current_fifo_buffer_offset_bytes); -+ ADVANCE_AT_REQ_OR_AVAIL(gyro_y_requested, gyr_avail, -+ (u8 *)&temp_data[0], -+ current_sample_buffer_offset, -+ (u8 *)&fifo_data[0], -+ current_fifo_buffer_offset_bytes); -+ ADVANCE_AT_REQ_OR_AVAIL(gyro_z_requested, gyr_avail, -+ (u8 *)&temp_data[0], -+ current_sample_buffer_offset, -+ (u8 *)&fifo_data[0], -+ current_fifo_buffer_offset_bytes); -+ ADVANCE_AT_REQ_OR_AVAIL(temp_requested, temp_avail, -+ (u8 *)&temp_data[0], -+ current_sample_buffer_offset, -+ (u8 *)&fifo_data[0], -+ current_fifo_buffer_offset_bytes); -+ -+#ifdef BMC150_BMI232_DEBUG_EN -+ /* The following is code only used for debugging */ -+ u16 timestamp = 0; -+ if (time_avail) { -+ memcpy((u8 *)×tamp, -+ (const u8 -+ *)(&fifo_data -+ [current_fifo_buffer_offset_bytes]), -+ 2); -+ current_fifo_buffer_offset_bytes += 2; -+ } -+ -+ u16 *debg = (u16 *)&temp_data[0]; -+ if (!time_avail) { -+ printk(KERN_WARNING -+ "bmi323 pushing to buffer %d/%d -- accel: %d %d %d gyro: %d %d %d", -+ (int)(f + 1), (int)available_frame_aggregates, -+ (int)(*((s16 *)&debg[0])), -+ (int)(*((s16 *)&debg[1])), -+ (int)(*((s16 *)&debg[2])), -+ (int)(*((s16 *)&debg[3])), -+ (int)(*((s16 *)&debg[4])), -+ (int)(*((s16 *)&debg[5]))); -+ } else { -+ printk(KERN_WARNING -+ "bmi323 pushing to buffer %d/%d -- time: %d accel: %d %d %d gyro: %d %d %d", -+ (int)(f + 1), (int)available_frame_aggregates, -+ (int)timestamp, (int)(*((s16 *)&debg[0])), -+ (int)(*((s16 *)&debg[1])), -+ (int)(*((s16 *)&debg[2])), -+ (int)(*((s16 *)&debg[3])), -+ (int)(*((s16 *)&debg[4])), -+ (int)(*((s16 *)&debg[5]))); -+ } -+#endif -+ -+ iio_push_to_buffers_with_timestamp( -+ indio_dev, &temp_data[0], -+ first_sample_timestamp_ns + -+ (fifo_frame_time_ns * (s64)j)); -+ } -+ -+bmi323_irq_done: -+ mutex_unlock(&indio_data->bmi323.mutex); -+ -+ /* -+ * Tell the core we are done with this trigger and ready for the -+ * next one. -+ */ -+ iio_trigger_notify_done(indio_dev->trig); -+ -+ return IRQ_HANDLED; -+} -+ -+int bmi323_set_trigger_state(struct iio_trigger *trig, bool state) -+{ -+ return 0; -+} -+ -+/* -+// The following is meant to be used in a IRQ-enabled hardware -+static const struct iio_trigger_ops time_trigger_ops = { -+ .set_trigger_state = &bmi323_set_trigger_state, -+ //.reenable = NULL, -+ .validate_device = &iio_trigger_validate_own_device, -+}; -+*/ -+ -+/* -+ * A very basic scan mask: everything can work in conjunction with everything else so no need to worry about -+ * managing conbinations of mutually exclusive data sources... -+ */ -+static const unsigned long bmi323_accel_scan_masks[] = { -+ BIT(BMI323_ACCEL_AXIS_X) | BIT(BMI323_ACCEL_AXIS_Y) | -+ BIT(BMI323_ACCEL_AXIS_Z) | BIT(BMI323_GYRO_AXIS_X) | -+ BIT(BMI323_GYRO_AXIS_Y) | -+ BIT(BMI323_GYRO_AXIS_Z) /*| BIT(BMI323_TEMP)*/, -+ 0 -+}; -+ -+int bmi323_iio_init(struct iio_dev *indio_dev) -+{ -+ struct bmc150_accel_data *data = iio_priv(indio_dev); -+ struct irq_data *irq_desc = NULL; -+ -+ if (data->bmi323.i2c_client != NULL) { -+ data->bmi323.dev = &data->bmi323.i2c_client->dev; -+ } else if (data->bmi323.spi_client != NULL) { -+ data->bmi323.dev = &data->bmi323.spi_client->dev; -+ } else { -+ return -ENODEV; -+ } -+ -+ int ret = 0; -+ -+ /* change to 8 for a default 200Hz sampling rate */ -+ const int gyr_odr_conf_idx = 7; -+ const int acc_odr_conf_idx = 7; -+ -+ mutex_init(&data->bmi323.mutex); -+ -+ data->bmi323.acc_odr_time_ns = -+ bmi323_accel_odr_map[acc_odr_conf_idx].time_ns; -+ data->bmi323.gyr_odr_time_ns = -+ bmi323_gyro_odr_map[gyr_odr_conf_idx].time_ns; -+ -+ // FIFO enabled for gyro, accel and temp. Overwrite older samples. -+ data->bmi323.fifo_conf_reg_value = cpu_to_le16((u16)0x0F00U); -+ //data->bmi323.fifo_conf_reg_value = cpu_to_le16((u16)0x0E00U); -+ //data->bmi323.fifo_conf_reg_value = cpu_to_le16((u16)0x0600U); // working -+ -+ // now set the (default) normal mode... -+ // normal mode: 0x4000 -+ // no averaging: 0x0000 -+ data->bmi323.acc_conf_reg_value = cpu_to_le16( -+ 0x4000 | ((u16)BMC150_BMI323_ACCEL_RANGE_2_VAL << (u16)4U) | -+ ((u16)bmi323_accel_odr_map[acc_odr_conf_idx].hw_val)); -+ -+ // now set the (default) normal mode... -+ // normal mode: 0x4000 -+ // no averaging: 0x0000 -+ // filtering to ODR/2: 0x0000 -+ data->bmi323.gyr_conf_reg_value = cpu_to_le16( -+ 0x4000 | ((u16)BMC150_BMI323_GYRO_RANGE_125_VAL << (u16)4U) | -+ ((u16)bmi323_gyro_odr_map[gyr_odr_conf_idx].hw_val)); -+ -+ // the datasheet states that FIFO buffer MUST be enabled before enabling any sensor -+ ret = bmi323_write_u16(&data->bmi323, BMC150_BMI323_FIFO_CONF_REG, -+ data->bmi323.fifo_conf_reg_value); -+ if (ret != 0) { -+ return -1; -+ } -+ -+ ret = bmi323_write_u16(&data->bmi323, BMC150_BMI323_ACC_CONF_REG, -+ data->bmi323.acc_conf_reg_value); -+ if (ret != 0) { -+ return -1; -+ } -+ -+ ret = bmi323_write_u16(&data->bmi323, BMC150_BMI323_GYR_CONF_REG, -+ data->bmi323.gyr_conf_reg_value); -+ if (ret != 0) { -+ return -2; -+ } -+ -+ indio_dev->channels = bmi323_channels; -+ indio_dev->num_channels = ARRAY_SIZE(bmi323_channels); -+ indio_dev->name = "bmi323"; -+ indio_dev->available_scan_masks = bmi323_accel_scan_masks; -+ indio_dev->modes = INDIO_DIRECT_MODE; -+ indio_dev->info = &bmi323_accel_info; -+ indio_dev->label = "bmi323-accel_base"; -+ -+ if (data->bmi323.irq > 0) { -+ dev_info(data->bmi323.dev, "IRQ pin reported as connected: %d", -+ data->bmi323.irq); -+ -+ irq_desc = irq_get_irq_data(data->bmi323.irq); -+ if (!irq_desc) { -+ dev_err(data->bmi323.dev, -+ "Could not find IRQ %d. ignoring it.\n", -+ data->bmi323.irq); -+ goto bmi323_iio_init_missing_irq_pin; -+ } -+ -+ //data->bmi323.trig[0] = devm_iio_trigger_alloc(data->bmi323.dev, "trig-fifo_full-%s-%d", indio_dev->name, iio_device_id(indio_dev)); -+ //if (data->bmi323.trig[0] == NULL) { -+ // ret = -ENOMEM; -+ // goto bmi323_iio_init_err_trigger_unregister; -+ //} -+ // -+ //data->bmi323.trig[0]->ops = &time_trigger_ops; -+ //iio_trigger_set_drvdata(data->bmi323.trig[0], indio_dev); -+ //ret = devm_iio_trigger_register(data->bmi323.dev, data->bmi323.trig[0]); -+ //if (ret) { -+ // dev_err(data->bmi323.dev, "iio trigger register failed\n"); -+ // goto bmi323_iio_init_err_trigger_unregister; -+ //} -+ -+ /* -+ * register triggers BEFORE buffer setup so that they are cleared -+ * on emergence exit by bmi323_iio_init_err_trigger_unregister. -+ * -+ * This is just a placeholder until I can get my hands on a bmi323 -+ * device that has the IRQ pin actually connected to the CPU. -+ */ -+ -+ /* here resume operation with the module part common to irq and non-irq enabled code. */ -+ goto bmi323_iio_init_common_irq_and_not_irq; -+ } -+ -+bmi323_iio_init_missing_irq_pin: -+ dev_info( -+ data->bmi323.dev, -+ "IRQ pin NOT connected (irq=%d). Will continue normally without triggers.", -+ data->bmi323.irq); -+ -+bmi323_iio_init_common_irq_and_not_irq: -+ -+ /* Once orientation matrix is implemented switch this to iio_triggered_buffer_setup_ext. */ -+ ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time, -+ iio_bmi323_trigger_h, -+ &bmi323_buffer_ops); -+ if (ret < 0) { -+ dev_err(data->bmi323.dev, -+ "Failed: iio triggered buffer setup: %d\n", ret); -+ goto bmi323_iio_init_err_trigger_unregister; -+ } -+ -+ ret = pm_runtime_set_active(data->bmi323.dev); -+ if (ret) { -+ dev_err(data->bmi323.dev, -+ "bmi323 unable to initialize runtime PD: pm_runtime_set_active returned %d\n", -+ ret); -+ goto bmi323_iio_init_err_buffer_cleanup; -+ } -+ -+ pm_runtime_enable(data->bmi323.dev); -+ pm_runtime_set_autosuspend_delay(data->bmi323.dev, -+ BMC150_BMI323_AUTO_SUSPEND_DELAY_MS); -+ pm_runtime_use_autosuspend(data->bmi323.dev); -+ -+ ret = iio_device_register(indio_dev); -+ if (ret < 0) { -+ dev_err(data->bmi323.dev, -+ "bmi323 unable to register iio device: %d\n", ret); -+ goto bmi323_iio_init_err_pm_cleanup; -+ } -+ -+ return 0; -+ -+bmi323_iio_init_err_pm_cleanup: -+ pm_runtime_dont_use_autosuspend(data->bmi323.dev); -+ pm_runtime_disable(data->bmi323.dev); -+bmi323_iio_init_err_buffer_cleanup: -+ iio_triggered_buffer_cleanup(indio_dev); -+bmi323_iio_init_err_trigger_unregister: -+ /* -+ * unregister triggers if they have been setup already. -+ * iio_trigger_unregister shall be used in that regard. -+ * -+ * This is just a placeholder until I can get my hands on a bmi323 -+ * device that has the IRQ pin actually connected to the CPU. -+ */ -+ //if (data->bmi323.trig[0] != NULL) { -+ // iio_trigger_unregister(data->bmi323.trig[0]); -+ //} -+ -+ return ret; -+} -+EXPORT_SYMBOL_NS_GPL(bmi323_iio_init, IIO_BMC150); -+ -+void bmi323_iio_deinit(struct iio_dev *indio_dev) -+{ -+ struct bmc150_accel_data *data = iio_priv(indio_dev); -+ struct device *dev = bmi323_get_managed_device(&data->bmi323); -+ -+ iio_device_unregister(indio_dev); -+ -+ pm_runtime_disable(dev); -+ pm_runtime_set_suspended(dev); -+ pm_runtime_put_noidle(dev); -+ -+ iio_triggered_buffer_cleanup(indio_dev); -+ -+ //iio_device_free(indio_dev); // this isn't done in the bmg160 driver nor in other drivers so I guess I shouldn't do it too -+ -+ mutex_unlock(&data->bmi323.mutex); -+ bmi323_chip_rst(&data->bmi323); -+ mutex_unlock(&data->bmi323.mutex); -+} -+EXPORT_SYMBOL_NS_GPL(bmi323_iio_deinit, IIO_BMC150); -+ -+#ifdef CONFIG_PM_SLEEP -+static int bmc150_accel_suspend(struct device *dev) - { - struct iio_dev *indio_dev = dev_get_drvdata(dev); - struct bmc150_accel_data *data = iio_priv(indio_dev); - -+ if (data->dev_type == BMI323) { -+ int ret; -+ -+ //dev_warn(dev, "bmi323 suspending driver..."); -+ -+ // here push the register GYRO & ACCEL configuration and issue a reset so that chip goes to sleep mode (the default one after a reset) -+ mutex_unlock(&data->bmi323.mutex); -+ -+ ret = bmi323_chip_rst(&data->bmi323); -+ mutex_unlock(&data->bmi323.mutex); -+ if (ret != 0) { -+ dev_err(dev, -+ "bmi323 error in suspend on bmi323_chip_rst: %d\n", -+ ret); -+ data->bmi323.flags |= BMI323_FLAGS_RESET_FAILED; -+ return -EAGAIN; -+ } -+ -+ return 0; -+ } -+ - mutex_lock(&data->mutex); - bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_SUSPEND, 0); - mutex_unlock(&data->mutex); -@@ -1844,6 +4005,63 @@ static int bmc150_accel_resume(struct device *dev) - struct iio_dev *indio_dev = dev_get_drvdata(dev); - struct bmc150_accel_data *data = iio_priv(indio_dev); - -+ if (data->dev_type == BMI323) { -+ int ret; -+ -+ //dev_warn(dev, "bmi323 resuming driver..."); -+ -+ // here pop the register GYRO & ACCEL configuration and issue a reset so that chip goes to sleep mode (the default one after a reset) -+ mutex_lock(&data->bmi323.mutex); -+ -+ // this was done already in runtime_sleep function. -+ if ((data->bmi323.flags & BMI323_FLAGS_RESET_FAILED) != 0x00U) { -+ ret = bmi323_chip_rst(&data->bmi323); -+ if (ret == 0) { -+ data->bmi323.flags &= -+ ~BMI323_FLAGS_RESET_FAILED; -+ } else { -+ goto bmi323_bmc150_accel_resume_terminate; -+ } -+ } -+ -+ ret = bmi323_write_u16(&data->bmi323, -+ BMC150_BMI323_FIFO_CONF_REG, -+ data->bmi323.fifo_conf_reg_value); -+ if (ret != 0) { -+ goto bmi323_bmc150_accel_resume_terminate; -+ } -+ -+ ret = bmi323_write_u16(&data->bmi323, -+ BMC150_BMI323_GYR_CONF_REG, -+ data->bmi323.gyr_conf_reg_value); -+ if (ret != 0) { -+ goto bmi323_bmc150_accel_resume_terminate; -+ } -+ -+ ret = bmi323_write_u16(&data->bmi323, -+ BMC150_BMI323_ACC_CONF_REG, -+ data->bmi323.acc_conf_reg_value); -+ if (ret != 0) { -+ goto bmi323_bmc150_accel_resume_terminate; -+ } -+ -+bmi323_bmc150_accel_resume_terminate: -+ mutex_unlock(&data->bmi323.mutex); -+ if (ret != 0) { -+ return -EAGAIN; -+ } -+ -+ /* -+ * datasheet says "Start-up time": suspend to high performance mode is tipically 30ms, -+ * however when setting this to 32 or even higher the first reading from the gyro (unlike accel part) -+ * is actually the (wrong) default value 0x8000 so it is better to sleep a bit longer -+ * to prevent issues and give time to the sensor to pick up first readings... -+ */ -+ msleep_interruptible(64); -+ -+ return 0; -+ } -+ - mutex_lock(&data->mutex); - bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_NORMAL, 0); - bmc150_accel_fifo_set_mode(data); -@@ -1863,6 +4081,25 @@ static int bmc150_accel_runtime_suspend(struct device *dev) - struct bmc150_accel_data *data = iio_priv(indio_dev); - int ret; - -+ if (data->dev_type == BMI323) { -+ //dev_warn(dev, "bmi323 suspending runtime..."); -+ -+ /* -+ * Every operation requiring this function have the mutex locked already: -+ * with mutex_lock(&data->bmi323.mutex); -+ */ -+ ret = bmi323_chip_rst(&data->bmi323); -+ if (ret != 0) { -+ dev_err(dev, -+ "bmi323 error in runtime_suspend on bmi323_chip_rst: %d\n", -+ ret); -+ data->bmi323.flags |= BMI323_FLAGS_RESET_FAILED; -+ return -EAGAIN; -+ } -+ -+ return 0; -+ } -+ - ret = bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_SUSPEND, 0); - if (ret < 0) - return -EAGAIN; -@@ -1877,6 +4114,70 @@ static int bmc150_accel_runtime_resume(struct device *dev) - int ret; - int sleep_val; - -+ if (data->dev_type == BMI323) { -+ //dev_warn(dev, "bmi323 resuming runtime..."); -+ -+ /* -+ * Every operation requiring this function have the mutex locked already: -+ * with mutex_lock(&data->bmi323.mutex); -+ */ -+ -+ // recover from a bad state if it was left that way on reuntime_suspend -+ if ((data->bmi323.flags & BMI323_FLAGS_RESET_FAILED) != 0x00U) { -+ ret = bmi323_chip_rst(&data->bmi323); -+ if (ret == 0) { -+ data->bmi323.flags &= -+ ~BMI323_FLAGS_RESET_FAILED; -+ } else { -+ goto bmi323_bmc150_accel_runtime_resume_terminate; -+ } -+ } -+ -+ ret = bmi323_write_u16(&data->bmi323, -+ BMC150_BMI323_FIFO_CONF_REG, -+ data->bmi323.fifo_conf_reg_value); -+ if (ret != 0) { -+ dev_err(dev, -+ "bmi323 writing to GYR_CONF register failed"); -+ goto bmi323_bmc150_accel_runtime_resume_terminate; -+ } -+ -+ ret = bmi323_write_u16(&data->bmi323, -+ BMC150_BMI323_GYR_CONF_REG, -+ data->bmi323.gyr_conf_reg_value); -+ if (ret != 0) { -+ dev_err(dev, -+ "bmi323 writing to GYR_CONF register failed"); -+ goto bmi323_bmc150_accel_runtime_resume_terminate; -+ } -+ -+ ret = bmi323_write_u16(&data->bmi323, -+ BMC150_BMI323_ACC_CONF_REG, -+ data->bmi323.acc_conf_reg_value); -+ if (ret != 0) { -+ dev_err(dev, -+ "bmi323 writing to ACC_CONF register failed"); -+ goto bmi323_bmc150_accel_runtime_resume_terminate; -+ } -+ -+bmi323_bmc150_accel_runtime_resume_terminate: -+ if (ret != 0) { -+ dev_err(dev, -+ "bmi323 bmc150_accel_runtime_resume -EAGAIN"); -+ return -EAGAIN; -+ } -+ -+ /* -+ * datasheet says "Start-up time": suspend to high performance mode is tipically 30ms, -+ * however when setting this to 32 or even higher the first reading from the gyro (unlike accel part) -+ * is actually the (wrong) default value 0x8000 so it is better to sleep a bit longer -+ * to prevent issues and give time to the sensor to pick up first readings... -+ */ -+ msleep_interruptible(64); -+ -+ return 0; -+ } -+ - ret = bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_NORMAL, 0); - if (ret < 0) - return ret; -diff --git a/drivers/iio/accel/bmc150-accel-i2c.c b/drivers/iio/accel/bmc150-accel-i2c.c -index ee1ba134ad42..0d6ee304b3e7 100644 ---- a/drivers/iio/accel/bmc150-accel-i2c.c -+++ b/drivers/iio/accel/bmc150-accel-i2c.c -@@ -173,15 +173,102 @@ static void bmc150_acpi_dual_accel_remove(struct i2c_client *client) {} - - static int bmc150_accel_probe(struct i2c_client *client) - { -+ int ret; -+ u8 chip_id_first[4] = { 0x00, 0x00, 0x00, 0x00 }; -+ enum bmc150_device_type dev_type = BMC150; - const struct i2c_device_id *id = i2c_client_get_device_id(client); - struct regmap *regmap; - const char *name = NULL; - enum bmc150_type type = BOSCH_UNKNOWN; -+ -+ /* reads 4 bytes (2 dummy + 2 good) from the i2c CHIP_ID device register */ -+ ret = i2c_smbus_read_i2c_block_data(client, 0x00, 4, &chip_id_first[0]); -+ if (ret != 4) { -+ dev_info( -+ &client->dev, -+ "error checking if the bmc150 is in fact a bmi323: i2c_smbus_read_i2c_block_data = %d: reg = 0x%02x.\n\tIt probably is a bmc150 as correctly reported by the ACPI entry.", -+ (int)ret, 0x00); -+ goto bmi150_old_probe; -+ } -+ -+ // at this point we have enough data to know what chip we are handling -+ dev_type = (chip_id_first[2] == 0x43) ? BMI323 : dev_type; -+ -+ if (dev_type == BMI323) { -+ dev_warn( -+ &client->dev, -+ "bmc323: what the ACPI table reported as a bmc150 is in fact a bmc323\n"); -+ -+ struct iio_dev *indio_dev = devm_iio_device_alloc( -+ &client->dev, sizeof(struct bmc150_accel_data)); -+ if (!indio_dev) { -+ dev_err(&client->dev, -+ "bmc323 init process failed: out of memory\n"); -+ -+ return -ENOMEM; -+ } -+ -+ dev_set_drvdata(&client->dev, indio_dev); -+ struct bmc150_accel_data *data = iio_priv(indio_dev); -+ data->dev_type = dev_type; -+ -+ struct bmi323_private_data *bmi323_data = &data->bmi323; -+ bmi323_data->i2c_client = client; -+ bmi323_data->spi_client = NULL; -+ bmi323_data->irq = client->irq; -+ -+ /* -+ * VDD is the analog and digital domain voltage supply -+ * VDDIO is the digital I/O voltage supply -+ */ -+ bmi323_data->regulators[0].supply = "vdd"; -+ bmi323_data->regulators[1].supply = "vddio"; -+ ret = devm_regulator_bulk_get( -+ &client->dev, ARRAY_SIZE(bmi323_data->regulators), -+ bmi323_data->regulators); -+ if (ret) { -+ return dev_err_probe(&client->dev, ret, -+ "failed to get regulators\n"); -+ } -+ -+ ret = regulator_bulk_enable(ARRAY_SIZE(bmi323_data->regulators), -+ bmi323_data->regulators); -+ if (ret) { -+ iio_device_free(indio_dev); -+ -+ dev_err(&client->dev, -+ "failed to enable regulators: %d\n", ret); -+ return ret; -+ } -+ -+ ret = bmi323_chip_rst(bmi323_data); -+ if (ret != 0) { -+ dev_err(&client->dev, -+ "bmc323: error issuing the chip reset: %d\n", -+ ret); -+ return ret; -+ } -+ -+ dev_info( -+ &client->dev, -+ "bmc323: chip reset success: starting the iio subsystem binding\n"); -+ -+ ret = bmi323_iio_init(indio_dev); -+ if (ret != 0) { -+ return ret; -+ } -+ -+ return 0; -+ } -+ -+bmi150_old_probe: -+ dev_info(&client->dev, -+ "executing the normal procedure for a bmc150..."); -+ - bool block_supported = - i2c_check_functionality(client->adapter, I2C_FUNC_I2C) || - i2c_check_functionality(client->adapter, - I2C_FUNC_SMBUS_READ_I2C_BLOCK); -- int ret; - - regmap = devm_regmap_init_i2c(client, &bmc150_regmap_conf); - if (IS_ERR(regmap)) { -@@ -198,7 +285,7 @@ static int bmc150_accel_probe(struct i2c_client *client) - type, name, block_supported); - if (ret) - return ret; -- -+ - /* - * The !id check avoids recursion when probe() gets called - * for the second client. -@@ -211,6 +298,15 @@ static int bmc150_accel_probe(struct i2c_client *client) - - static void bmc150_accel_remove(struct i2c_client *client) - { -+ struct iio_dev *indio_dev = dev_get_drvdata(&client->dev); -+ struct bmc150_accel_data *data = iio_priv(indio_dev); -+ -+ if (data->dev_type == BMI323) { -+ bmi323_iio_deinit(indio_dev); -+ -+ return; -+ } -+ - bmc150_acpi_dual_accel_remove(client); - - bmc150_accel_core_remove(&client->dev); -diff --git a/drivers/iio/accel/bmc150-accel.h b/drivers/iio/accel/bmc150-accel.h -index 7775c5edaeef..65ec208960df 100644 ---- a/drivers/iio/accel/bmc150-accel.h -+++ b/drivers/iio/accel/bmc150-accel.h -@@ -8,6 +8,14 @@ - #include <linux/regulator/consumer.h> - #include <linux/workqueue.h> - -+/* -+ * the bmi323 needs raw access to spi and i2c: I cannot use regmap -+ * as this device expects i2c writes to be 2 bytes, -+ * spi reads to be 3 bytes and i2c reads to be 4 bytes. -+ */ -+#include <linux/i2c.h> -+#include <linux/spi/spi.h> -+ - struct regmap; - struct i2c_client; - struct bmc150_accel_chip_info; -@@ -34,6 +42,11 @@ struct bmc150_accel_interrupt { - atomic_t users; - }; - -+enum bmc150_device_type { -+ BMC150, -+ BMI323, -+}; -+ - struct bmc150_accel_trigger { - struct bmc150_accel_data *data; - struct iio_trigger *indio_trig; -@@ -55,6 +68,25 @@ enum bmc150_accel_trigger_id { - BMC150_ACCEL_TRIGGERS, - }; - -+#define BMI323_FLAGS_RESET_FAILED 0x00000001U -+ -+struct bmi323_private_data { -+ struct regulator_bulk_data regulators[2]; -+ struct i2c_client *i2c_client; -+ struct spi_device *spi_client; -+ struct device *dev; /* pointer at i2c_client->dev or spi_client->dev */ -+ struct mutex mutex; -+ int irq; -+ u32 flags; -+ u16 acc_conf_reg_value; -+ u16 gyr_conf_reg_value; -+ u16 fifo_conf_reg_value; -+ struct iio_trigger *trig[1]; -+ s64 fifo_frame_time_diff_ns; -+ s64 acc_odr_time_ns; -+ s64 gyr_odr_time_ns; -+}; -+ - struct bmc150_accel_data { - struct regmap *regmap; - struct regulator_bulk_data regulators[2]; -@@ -83,7 +115,67 @@ struct bmc150_accel_data { - void (*resume_callback)(struct device *dev); - struct delayed_work resume_work; - struct iio_mount_matrix orientation; --}; -+ enum bmc150_device_type dev_type; -+ struct bmi323_private_data bmi323; -+ }; -+ -+/** -+ * This function performs a write of a u16 little-endian (regardless of CPU architecture) integer -+ * to a device register. Returns 0 on success or an error code otherwise. -+ * -+ * PRE: in_value holds the data to be sent to the sensor, in little endian format even on big endian -+ * architectures. -+ * -+ * NOTE: bmi323->dev can be NULL (not yet initialized) when this function is called -+ * therefore it is not needed and is not used inside the function -+ * -+ * WARNING: this function does not lock any mutex and synchronization MUST be performed by the caller -+ */ -+int bmi323_write_u16(struct bmi323_private_data *bmi323, u8 in_reg, u16 in_value); -+ -+/** -+ * This function performs a read of "good" values from the bmi323 discarding what -+ * in the datasheet is described as "dummy data": additional useles bytes. -+ * -+ * PRE: bmi323 has been partially initialized: i2c_device and spi_devices MUST be set to either -+ * the correct value or NULL -+ * -+ * NOTE: bmi323->dev can be NULL (not yet initialized) when this function is called -+ * therefore it is not needed and is not used inside the function -+ * -+ * POST: on success out_value is written with data from the sensor, as it came out, so the -+ * content is little-endian even on big endian architectures -+ * -+ * WARNING: this function does not lock any mutex and synchronization MUST be performed by the caller -+ */ -+int bmi323_read_u16(struct bmi323_private_data *bmi323, u8 in_reg, u16* out_value); -+ -+int bmi323_chip_check(struct bmi323_private_data *bmi323); -+ -+/** -+ * Reset the chip in a known state that is ready to accept commands, but is not configured therefore after calling this function -+ * it is required to load a new configuration to start data acquisition. -+ * -+ * PRE: bmi323 has been fully identified and partially initialized -+ * -+ * NOTE: after issuing a reset the the chip will be in what it is called "suspended mode" and the feature angine is -+ * ready to be set. This mode has everything disabled and consumes aroud 15uA. -+ * -+ * When removing the driver or suspend has been requested it's best to reset the chip so that power consumption -+ * will be the lowest possible. -+ */ -+int bmi323_chip_rst(struct bmi323_private_data *bmi323); -+ -+/** -+ * This function MUST be called in probe and is responsible for registering the userspace sysfs. -+ * -+ * The indio_dev MUST have been allocated but not registered. This function will perform userspace registration. -+ * -+ * @param indio_dev the industrual io device already allocated but not yet registered -+ */ -+int bmi323_iio_init(struct iio_dev *indio_dev); -+ -+void bmi323_iio_deinit(struct iio_dev *indio_dev); - - int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq, - enum bmc150_type type, const char *name, --- -2.42.0 - diff --git a/0001-hid-asus-reset-the-backlight-brightness-level-on-resume.patch b/0001-hid-asus-reset-the-backlight-brightness-level-on-resume.patch deleted file mode 100644 index 59698ca0f7cc..000000000000 --- a/0001-hid-asus-reset-the-backlight-brightness-level-on-resume.patch +++ /dev/null @@ -1,59 +0,0 @@ -From ca054bb924b349c586d783e4473c4cab404c40a1 Mon Sep 17 00:00:00 2001 -From: Denis Benato <benato.denis96@gmail.com> -Date: Fri, 17 Nov 2023 14:15:56 +1300 -Subject: [PATCH] HID: hid-asus: reset the backlight brightness level on resume - -Some devices managed by this driver automatically set brightness to 0 -before entering a suspended state and reset it back to a default -brightness level after the resume: -this has the effect of having the kernel report wrong brightness -status after a sleep, and on some devices (like the Asus RC71L) that -brightness is the intensity of LEDs directly facing the user. - -Fix the above issue by setting back brightness to the level it had -before entering a sleep state. - -Signed-off-by: Denis Benato <benato.denis96@gmail.com> -Signed-off-by: Luke D. Jones <luke@ljones.dev> -Signed-off-by: Jiri Kosina <jkosina@suse.cz> ---- - drivers/hid/hid-asus.c | 19 +++++++++++++++++++ - 1 file changed, 19 insertions(+) - -diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c -index b70673a929a1ed..78cdfb8b9a7aeb 100644 ---- a/drivers/hid/hid-asus.c -+++ b/drivers/hid/hid-asus.c -@@ -1000,6 +1000,24 @@ static int asus_start_multitouch(struct hid_device *hdev) - return 0; - } - -+static int __maybe_unused asus_resume(struct hid_device *hdev) { -+ struct asus_drvdata *drvdata = hid_get_drvdata(hdev); -+ int ret = 0; -+ -+ if (drvdata->kbd_backlight) { -+ const u8 buf[] = { FEATURE_KBD_REPORT_ID, 0xba, 0xc5, 0xc4, -+ drvdata->kbd_backlight->cdev.brightness }; -+ ret = asus_kbd_set_report(hdev, buf, sizeof(buf)); -+ if (ret < 0) { -+ hid_err(hdev, "Asus failed to set keyboard backlight: %d\n", ret); -+ goto asus_resume_err; -+ } -+ } -+ -+asus_resume_err: -+ return ret; -+} -+ - static int __maybe_unused asus_reset_resume(struct hid_device *hdev) - { - struct asus_drvdata *drvdata = hid_get_drvdata(hdev); -@@ -1294,6 +1312,7 @@ static struct hid_driver asus_driver = { - .input_configured = asus_input_configured, - #ifdef CONFIG_PM - .reset_resume = asus_reset_resume, -+ .resume = asus_resume, - #endif - .event = asus_event, - .raw_event = asus_raw_event diff --git a/0001-iio-imu_Add_driver_for_BMI323_IMU.patch b/0001-iio-imu_Add_driver_for_BMI323_IMU.patch new file mode 100644 index 000000000000..bf53ac8652ef --- /dev/null +++ b/0001-iio-imu_Add_driver_for_BMI323_IMU.patch @@ -0,0 +1,2810 @@ +Add devicetree description document for Bosch BMI323, a 6-Axis IMU. + +Signed-off-by: Jagath Jog J <jagathjog1996@gmail.com> +Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> +--- + .../bindings/iio/imu/bosch,bmi323.yaml | 77 +++++++++++++++++++ + 1 file changed, 77 insertions(+) + create mode 100644 Documentation/devicetree/bindings/iio/imu/bosch,bmi323.yaml + +diff --git a/Documentation/devicetree/bindings/iio/imu/bosch,bmi323.yaml b/Documentation/devicetree/bindings/iio/imu/bosch,bmi323.yaml +new file mode 100644 +index 000000000000..64ef26e19669 +--- /dev/null ++++ b/Documentation/devicetree/bindings/iio/imu/bosch,bmi323.yaml +@@ -0,0 +1,77 @@ ++# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/iio/imu/bosch,bmi323.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Bosch BMI323 6-Axis IMU ++ ++maintainers: ++ - Jagath Jog J <jagathjog1996@gmail.com> ++ ++description: ++ BMI323 is a 6-axis inertial measurement unit that supports acceleration and ++ gyroscopic measurements with hardware fifo buffering. Sensor also provides ++ events information such as motion, steps, orientation, single and double ++ tap detection. ++ ++properties: ++ compatible: ++ const: bosch,bmi323 ++ ++ reg: ++ maxItems: 1 ++ ++ vdd-supply: true ++ vddio-supply: true ++ ++ interrupts: ++ minItems: 1 ++ maxItems: 2 ++ ++ interrupt-names: ++ minItems: 1 ++ maxItems: 2 ++ items: ++ enum: ++ - INT1 ++ - INT2 ++ ++ drive-open-drain: ++ description: ++ set if the specified interrupt pin should be configured as ++ open drain. If not set, defaults to push-pull. ++ ++ mount-matrix: ++ description: ++ an optional 3x3 mounting rotation matrix. ++ ++required: ++ - compatible ++ - reg ++ - vdd-supply ++ - vddio-supply ++ ++allOf: ++ - $ref: /schemas/spi/spi-peripheral-props.yaml# ++ ++unevaluatedProperties: false ++ ++examples: ++ - | ++ // Example for I2C ++ #include <dt-bindings/interrupt-controller/irq.h> ++ i2c { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ imu@68 { ++ compatible = "bosch,bmi323"; ++ reg = <0x68>; ++ vddio-supply = <&vddio>; ++ vdd-supply = <&vdd>; ++ interrupt-parent = <&gpio1>; ++ interrupts = <29 IRQ_TYPE_EDGE_RISING>; ++ interrupt-names = "INT1"; ++ }; ++ }; +From: Jagath Jog J <jagathjog1996@gmail.com> +To: jic23@kernel.org, andriy.shevchenko@linux.intel.com, + lars@metafoo.de, robh+dt@kernel.org, + krzysztof.kozlowski+dt@linaro.org +Cc: linux-iio@vger.kernel.org, devicetree@vger.kernel.org, + linux-kernel@vger.kernel.org +Subject: [RFC 2/2] iio: imu: Add driver for BMI323 IMU +Date: Mon, 18 Sep 2023 13:33:14 +0530 [thread overview] +Message-ID: <20230918080314.11959-3-jagathjog1996@gmail.com> (raw) +In-Reply-To: <20230918080314.11959-1-jagathjog1996@gmail.com> + +The Bosch BMI323 is a 6-axis low-power IMU that provide measurements for +acceleration, angular rate, and temperature. This sensor includes +motion-triggered interrupt features, such as a step counter, tap detection, +and activity/inactivity interrupt capabilities. + +The driver supports various functionalities, including data ready, FIFO +data handling, and events such as tap detection, step counting, and +activity interrupts. + +Signed-off-by: Jagath Jog J <jagathjog1996@gmail.com> +--- + MAINTAINERS | 7 + + drivers/iio/imu/Kconfig | 1 + + drivers/iio/imu/Makefile | 1 + + drivers/iio/imu/bmi323/Kconfig | 33 + + drivers/iio/imu/bmi323/Makefile | 7 + + drivers/iio/imu/bmi323/bmi323.h | 209 +++ + drivers/iio/imu/bmi323/bmi323_core.c | 2139 +++++++++++++++++++++++ + drivers/iio/imu/bmi323/bmi323_i2c.c | 121 ++ + drivers/iio/imu/bmi323/bmi323_spi.c | 92 + + 10 files changed, 2628 insertions(+) + create mode 100644 drivers/iio/imu/bmi323/Kconfig + create mode 100644 drivers/iio/imu/bmi323/Makefile + create mode 100644 drivers/iio/imu/bmi323/bmi323.h + create mode 100644 drivers/iio/imu/bmi323/bmi323_core.c + create mode 100644 drivers/iio/imu/bmi323/bmi323_i2c.c + create mode 100644 drivers/iio/imu/bmi323/bmi323_spi.c + +diff --git a/MAINTAINERS b/MAINTAINERS +index 4e07c032d06a..47ca415212a7 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -3595,6 +3595,13 @@ S: Maintained + F: Documentation/devicetree/bindings/iio/accel/bosch,bma400.yaml + F: drivers/iio/accel/bma400* + ++BOSCH SENSORTEC BMI323 IMU IIO DRIVER ++M: Jagath Jog J <jagathjog1996@gmail.com> ++L: linux-iio@vger.kernel.org ++S: Maintained ++F: Documentation/devicetree/bindings/iio/imu/bosch,bma400.yaml ++F: drivers/iio/imu/bmi323/ ++ + BPF JIT for ARM + M: Shubham Bansal <illusionist.neo@gmail.com> + L: bpf@vger.kernel.org +diff --git a/drivers/iio/imu/Kconfig b/drivers/iio/imu/Kconfig +index c2f97629e9cd..6c9a85294bc1 100644 +--- a/drivers/iio/imu/Kconfig ++++ b/drivers/iio/imu/Kconfig +@@ -54,6 +54,7 @@ config ADIS16480 + + source "drivers/iio/imu/bmi160/Kconfig" + source "drivers/iio/imu/bno055/Kconfig" ++source "drivers/iio/imu/bmi323/Kconfig" + + config FXOS8700 + tristate +diff --git a/drivers/iio/imu/Makefile b/drivers/iio/imu/Makefile +index 6eb612034722..627406476357 100644 +--- a/drivers/iio/imu/Makefile ++++ b/drivers/iio/imu/Makefile +@@ -16,6 +16,7 @@ obj-$(CONFIG_IIO_ADIS_LIB) += adis_lib.o + + obj-y += bmi160/ + obj-y += bno055/ ++obj-y += bmi323/ + + obj-$(CONFIG_FXOS8700) += fxos8700_core.o + obj-$(CONFIG_FXOS8700_I2C) += fxos8700_i2c.o +diff --git a/drivers/iio/imu/bmi323/Kconfig b/drivers/iio/imu/bmi323/Kconfig +new file mode 100644 +index 000000000000..ab37b285393c +--- /dev/null ++++ b/drivers/iio/imu/bmi323/Kconfig +@@ -0,0 +1,33 @@ ++# SPDX-License-Identifier: GPL-2.0 ++# ++# BMI323 IMU driver ++# ++ ++config BMI323 ++ tristate ++ select IIO_BUFFER ++ select IIO_TRIGGERED_BUFFER ++ ++config BMI323_I2C ++ tristate "Bosch BMI323 I2C driver" ++ depends on I2C ++ select BMI323 ++ select REGMAP_I2C ++ help ++ Enable support for the Bosch BMI323 6-Axis IMU connected to I2C ++ interface. ++ ++ This driver can also be built as a module. If so, the module will be ++ called bmi323_i2c. ++ ++config BMI323_SPI ++ tristate "Bosch BMI323 SPI driver" ++ depends on SPI ++ select BMI323 ++ select REGMAP_SPI ++ help ++ Enable support for the Bosch BMI323 6-Axis IMU connected to SPI ++ interface. ++ ++ This driver can also be built as a module. If so, the module will be ++ called bmi323_spi. +diff --git a/drivers/iio/imu/bmi323/Makefile b/drivers/iio/imu/bmi323/Makefile +new file mode 100644 +index 000000000000..a6a6dc0207c9 +--- /dev/null ++++ b/drivers/iio/imu/bmi323/Makefile +@@ -0,0 +1,7 @@ ++# SPDX-License-Identifier: GPL-2.0 ++# ++# Makefile for Bosch BMI323 IMU ++# ++obj-$(CONFIG_BMI323) += bmi323_core.o ++obj-$(CONFIG_BMI323_I2C) += bmi323_i2c.o ++obj-$(CONFIG_BMI323_SPI) += bmi323_spi.o +diff --git a/drivers/iio/imu/bmi323/bmi323.h b/drivers/iio/imu/bmi323/bmi323.h +new file mode 100644 +index 000000000000..dff126d41658 +--- /dev/null ++++ b/drivers/iio/imu/bmi323/bmi323.h +@@ -0,0 +1,209 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * IIO driver for Bosch BMI323 6-Axis IMU ++ * ++ * Copyright (C) 2023, Jagath Jog J <jagathjog1996@gmail.com> ++ */ ++ ++#ifndef _BMI323_H_ ++#define _BMI323_H_ ++ ++#include <linux/bits.h> ++#include <linux/regmap.h> ++#include <linux/units.h> ++ ++#define BMI323_I2C_DUMMY 2 ++#define BMI323_SPI_DUMMY 1 ++ ++/* Register map */ ++ ++#define BMI323_CHIP_ID_REG 0x00 ++#define BMI323_CHIP_ID_VAL 0x0043 ++#define BMI323_CHIP_ID_MSK GENMASK(7, 0) ++#define BMI323_ERR_REG 0x01 ++#define BMI323_STATUS_REG 0x02 ++#define BMI323_STATUS_POR_MSK BIT(0) ++ ++/* Accelero/Gyro/Temp data registers */ ++#define BMI323_ACCEL_X_REG 0x03 ++#define BMI323_GYRO_X_REG 0x06 ++#define BMI323_TEMP_REG 0x09 ++#define BMI323_ALL_CHAN_MSK GENMASK(5, 0) ++ ++/* Status registers */ ++#define BMI323_STATUS_INT1_REG 0x0D ++#define BMI323_STATUS_INT2_REG 0x0E ++#define BMI323_STATUS_NOMOTION_MSK BIT(0) ++#define BMI323_STATUS_MOTION_MSK BIT(1) ++#define BMI323_STATUS_STP_WTR_MSK BIT(5) ++#define BMI323_STATUS_TAP_MSK BIT(8) ++#define BMI323_STATUS_ERROR_MSK BIT(10) ++#define BMI323_STATUS_TMP_DRDY_MSK BIT(11) ++#define BMI323_STATUS_GYR_DRDY_MSK BIT(12) ++#define BMI323_STATUS_ACC_DRDY_MSK BIT(13) ++#define BMI323_STATUS_ACC_GYR_DRDY_MSK GENMASK(13, 12) ++#define BMI323_STATUS_FIFO_WTRMRK_MSK BIT(14) ++#define BMI323_STATUS_FIFO_FULL_MSK BIT(15) ++ ++/* Feature registers */ ++#define BMI323_FEAT_IO0_REG 0x10 ++#define BMI323_FEAT_IO0_XYZ_NOMOTION_MSK GENMASK(2, 0) ++#define BMI323_FEAT_IO0_XYZ_MOTION_MSK GENMASK(5, 3) ++#define BMI323_FEAT_XYZ_MSK GENMASK(2, 0) ++#define BMI323_FEAT_IO0_STP_CNT_MSK BIT(9) ++#define BMI323_FEAT_IO0_S_TAP_MSK BIT(12) ++#define BMI323_FEAT_IO0_D_TAP_MSK BIT(13) ++#define BMI323_FEAT_IO1_REG 0x11 ++#define BMI323_FEAT_IO1_ERR_MSK GENMASK(3, 0) ++#define BMI323_FEAT_IO2_REG 0x12 ++#define BMI323_FEAT_IO_STATUS_REG 0x14 ++#define BMI323_FEAT_IO_STATUS_MSK BIT(0) ++#define BMI323_FEAT_ENG_POLL 2000 ++#define BMI323_FEAT_ENG_TIMEOUT 10000 ++ ++/* FIFO registers */ ++#define BMI323_FIFO_FILL_LEVEL_REG 0x15 ++#define BMI323_FIFO_DATA_REG 0x16 ++ ++/* Accelero/Gyro config registers */ ++#define BMI323_ACC_CONF_REG 0x20 ++#define BMI323_GYRO_CONF_REG 0x21 ++#define BMI323_ACC_GYRO_CONF_MODE_MSK GENMASK(14, 12) ++#define BMI323_ACC_GYRO_CONF_ODR_MSK GENMASK(3, 0) ++#define BMI323_ACC_GYRO_CONF_SCL_MSK GENMASK(6, 4) ++#define BMI323_ACC_GYRO_CONF_BW_MSK BIT(7) ++#define BMI323_ACC_GYRO_CONF_AVG_MSK GENMASK(10, 8) ++ ++/* FIFO registers */ ++#define BMI323_FIFO_WTRMRK_REG 0x35 ++#define BMI323_FIFO_CONF_REG 0x36 ++#define BMI323_FIFO_CONF_STP_FUL_MSK BIT(0) ++#define BMI323_FIFO_CONF_ACC_GYR_EN_MSK GENMASK(10, 9) ++#define BMI323_FIFO_ACC_GYR_MSK GENMASK(1, 0) ++#define BMI323_FIFO_CTRL_REG 0x37 ++#define BMI323_FIFO_FLUSH_MSK BIT(0) ++ ++/* Interrupt pin config registers */ ++#define BMI323_IO_INT_CTR_REG 0x38 ++#define BMI323_IO_INT1_LVL_MSK BIT(0) ++#define BMI323_IO_INT1_OD_MSK BIT(1) ++#define BMI323_IO_INT1_OP_EN_MSK BIT(2) ++#define BMI323_IO_INT1_LVL_OD_OP_MSK GENMASK(2, 0) ++#define BMI323_IO_INT2_LVL_MSK BIT(8) ++#define BMI323_IO_INT2_OD_MSK BIT(9) ++#define BMI323_IO_INT2_OP_EN_MSK BIT(10) ++#define BMI323_IO_INT2_LVL_OD_OP_MSK GENMASK(10, 8) ++#define BMI323_IO_INT_CONF_REG 0x39 ++#define BMI323_IO_INT_LTCH_MSK BIT(0) ++#define BMI323_INT_MAP1_REG 0x3A ++#define BMI323_INT_MAP2_REG 0x3B ++#define BMI323_NOMOTION_MSK GENMASK(1, 0) ++#define BMI323_MOTION_MSK GENMASK(3, 2) ++#define BMI323_STEP_CNT_MSK GENMASK(11, 10) ++#define BMI323_TAP_MSK GENMASK(1, 0) ++#define BMI323_TMP_DRDY_MSK GENMASK(7, 6) ++#define BMI323_GYR_DRDY_MSK GENMASK(9, 8) ++#define BMI323_ACC_DRDY_MSK GENMASK(11, 10) ++#define BMI323_FIFO_WTRMRK_MSK GENMASK(13, 12) ++#define BMI323_FIFO_FULL_MSK GENMASK(15, 14) ++ ++/* Feature registers */ ++#define BMI323_FEAT_CTRL_REG 0x40 ++#define BMI323_FEAT_ENG_EN_MSK BIT(0) ++#define BMI323_FEAT_DATA_ADDR 0x41 ++#define BMI323_FEAT_DATA_TX 0x42 ++#define BMI323_FEAT_DATA_STATUS 0x43 ++#define BMI323_FEAT_DATA_TX_RDY_MSK BIT(1) ++#define BMI323_FEAT_EVNT_EXT_REG 0x47 ++#define BMI323_FEAT_EVNT_EXT_S_MSK BIT(3) ++#define BMI323_FEAT_EVNT_EXT_D_MSK BIT(4) ++ ++#define BMI323_CMD_REG 0x7E ++#define BMI323_RST_VAL 0xDEAF ++#define BMI323_CFG_RES_REG 0x7F ++ ++/* Extended registers */ ++#define BMI323_GEN_SET1_REG 0x02 ++#define BMI323_GEN_SET1_MODE_MSK BIT(0) ++#define BMI323_GEN_HOLD_DUR_MSK GENMASK(4, 1) ++ ++/* Any Motion/No Motion config registers */ ++#define BMI323_ANYMO1_REG 0x05 ++#define BMI323_NOMO1_REG 0x08 ++#define BMI323_MO2_OFFSET 0x01 ++#define BMI323_MO3_OFFSET 0x02 ++#define BMI323_MO1_REF_UP_MSK BIT(12) ++#define BMI323_MO1_SLOPE_TH_MSK GENMASK(11, 0) ++#define BMI323_MO2_HYSTR_MSK GENMASK(9, 0) ++#define BMI323_MO3_DURA_MSK GENMASK(12, 0) ++ ++/* Step counter config registers */ ++#define BMI323_STEP_SC1_REG 0x10 ++#define BMI323_STEP_SC1_WTRMRK_MSK GENMASK(9, 0) ++#define BMI323_STEP_SC1_RST_CNT_MSK BIT(10) ++#define BMI323_STEP_SC1_REG 0x10 ++#define BMI323_STEP_LEN 2 ++ ++/* Tap gesture config registers */ ++#define BMI323_TAP1_REG 0x1E ++#define BMI323_TAP1_AXIS_SEL_MSK GENMASK(1, 0) ++#define BMI323_AXIS_XYZ_MSK GENMASK(1, 0) ++#define BMI323_TAP1_TIMOUT_MSK BIT(2) ++#define BMI323_TAP1_MAX_PEAKS_MSK GENMASK(5, 3) ++#define BMI323_TAP1_MODE_MSK GENMASK(7, 6) ++#define BMI323_TAP2_REG 0x1F ++#define BMI323_TAP2_THRES_MSK GENMASK(9, 0) ++#define BMI323_TAP2_MAX_DUR_MSK GENMASK(15, 10) ++#define BMI323_TAP3_REG 0x20 ++#define BMI323_TAP3_QUIET_TIM_MSK GENMASK(15, 12) ++#define BMI323_TAP3_QT_BW_TAP_MSK GENMASK(11, 8) ++#define BMI323_TAP3_QT_AFT_GES_MSK GENMASK(15, 12) ++ ++#define BMI323_MOTION_THRES_SCALE 512 ++#define BMI323_MOTION_HYSTR_SCALE 512 ++#define BMI323_MOTION_DURAT_SCALE 50 ++#define BMI323_TAP_THRES_SCALE 512 ++#define BMI323_DUR_BW_TAP_SCALE 200 ++#define BMI323_QUITE_TIM_GES_SCALE 25 ++#define BMI323_MAX_GES_DUR_SCALE 25 ++ ++/* ++ * The formula to calculate temperature in C. ++ * See datasheet section 6.1.1, Register Map Overview ++ * ++ * T_C = (temp_raw / 512) + 23 ++ */ ++#define BMI323_TEMP_OFFSET 11776 ++#define BMI323_TEMP_SCALE 1953125 ++ ++/* ++ * The BMI323 features a FIFO with a capacity of 2048 bytes. Each frame ++ * consists of accelerometer (X, Y, Z) data and gyroscope (X, Y, Z) data, ++ * totaling 6 words or 12 bytes. The FIFO buffer can hold a total of ++ * 170 frames. ++ * ++ * If a watermark interrupt is configured for 170 frames, the interrupt will ++ * trigger when the FIFO reaches 169 frames, so limit the maximum watermark ++ * level to 169 frames. In terms of data, 169 frames would equal 1014 bytes, ++ * which is approximately 2 frames before the FIFO reaches its full capacity. ++ * See datasheet section 5.7.3 FIFO Buffer Interrupts ++ */ ++#define BMI323_BYTES_PER_SAMPLE 2 ++#define BMI323_FIFO_LENGTH_IN_BYTES 2048 ++#define BMI323_FIFO_FRAME_LENGTH 6 ++#define BMI323_FIFO_FULL_IN_FRAMES \ ++ ((BMI323_FIFO_LENGTH_IN_BYTES / \ ++ (BMI323_BYTES_PER_SAMPLE * BMI323_FIFO_FRAME_LENGTH)) - 1) ++#define BMI323_FIFO_FULL_IN_WORDS \ ++ (BMI323_FIFO_FULL_IN_FRAMES * BMI323_FIFO_FRAME_LENGTH) ++ ++#define BMI323_INT_MICRO_TO_RAW(val, val2, scale) ((val) * (scale) + \ ++ ((val2) * (scale)) / MEGA) ++ ++#define BMI323_RAW_TO_MICRO(raw, scale) ((((raw) % (scale)) * MEGA) / scale) ++ ++struct device; ++int bmi323_core_probe(struct device *dev); ++extern const struct regmap_config bmi323_regmap_config; ++ ++#endif +diff --git a/drivers/iio/imu/bmi323/bmi323_core.c b/drivers/iio/imu/bmi323/bmi323_core.c +new file mode 100644 +index 000000000000..0bd5dedd9a63 +--- /dev/null ++++ b/drivers/iio/imu/bmi323/bmi323_core.c +@@ -0,0 +1,2139 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * IIO core driver for Bosch BMI323 6-Axis IMU. ++ * ++ * Copyright (C) 2023, Jagath Jog J <jagathjog1996@gmail.com> ++ * ++ * Datasheet: https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmi323-ds000.pdf ++ */ ++ ++#include <linux/bitfield.h> ++#include <linux/cleanup.h> ++#include <linux/device.h> ++#include <linux/interrupt.h> ++#include <linux/minmax.h> ++#include <linux/module.h> ++#include <linux/mutex.h> ++#include <linux/property.h> ++#include <linux/regmap.h> ++#include <linux/regulator/consumer.h> ++#include <linux/units.h> ++ ++#include <asm/unaligned.h> ++ ++#include <linux/iio/buffer.h> ++#include <linux/iio/events.h> ++#include <linux/iio/iio.h> ++#include <linux/iio/sysfs.h> ++#include <linux/iio/trigger.h> ++#include <linux/iio/trigger_consumer.h> ++#include <linux/iio/triggered_buffer.h> ++ ++#include "bmi323.h" ++ ++enum bmi323_sensor_type { ++ BMI323_ACCEL, ++ BMI323_GYRO, ++ BMI323_SENSORS_CNT, ++}; ++ ++enum bmi323_opr_mode { ++ ACC_GYRO_MODE_DISABLE = 0x00, ++ GYRO_DRIVE_MODE_ENABLED = 0x01, ++ ACC_GYRO_MODE_DUTYCYCLE = 0x03, ++ ACC_GYRO_MODE_CONTINOUS = 0x04, ++ ACC_GYRO_MODE_HIGH_PERF = 0x07, ++}; ++ ++enum bmi323_state { ++ BMI323_IDLE, ++ BMI323_BUFFER_DRDY_TRIGGERED, ++ BMI323_BUFFER_FIFO, ++}; ++ ++enum bmi323_irq_pin { ++ BMI323_IRQ_DISABLED, ++ BMI323_IRQ_INT1, ++ BMI323_IRQ_INT2, ++}; ++ ++enum bmi323_3db_bw { ++ BMI323_BW_ODR_BY_2, ++ BMI323_BW_ODR_BY_4, ++}; ++ ++enum bmi323_scan { ++ BMI323_ACCEL_X, ++ BMI323_ACCEL_Y, ++ BMI323_ACCEL_Z, ++ BMI323_GYRO_X, ++ BMI323_GYRO_Y, ++ BMI323_GYRO_Z, ++ BMI323_CHAN_MAX ++}; ++ ++struct bmi323_hw { ++ u8 data; ++ u8 config; ++ const int (*scale_table)[2]; ++ int scale_table_len; ++}; ++ ++/* ++ * The accelerometer supports +-2G/4G/8G/16G ranges, and the resolution of ++ * each sample is 16 bits, signed. ++ * At +-8G the scale can calculated by ++ * ((8 + 8) * 9.80665 / (2^16 - 1)) * 10^6 = 2394.23819 scale in micro ++ * ++ */ ++static const int bmi323_accel_scale[][2] = { ++ { 0, 598 }, ++ { 0, 1197 }, ++ { 0, 2394 }, ++ { 0, 4788 }, ++}; ++ ++static const int bmi323_gyro_scale[][2] = { ++ { 0, 66 }, ++ { 0, 133 }, ++ { 0, 266 }, ++ { 0, 532 }, ++ { 0, 1065 }, ++}; ++ ++static const int bmi323_accel_gyro_avrg[] = {0, 2, 4, 8, 16, 32, 64}; ++ ++static const struct bmi323_hw bmi323_hw[2] = { ++ [BMI323_ACCEL] = { ++ .data = BMI323_ACCEL_X_REG, ++ .config = BMI323_ACC_CONF_REG, ++ .scale_table = bmi323_accel_scale, ++ .scale_table_len = ARRAY_SIZE(bmi323_accel_scale), ++ }, ++ [BMI323_GYRO] = { ++ .data = BMI323_GYRO_X_REG, ++ .config = BMI323_GYRO_CONF_REG, ++ .scale_table = bmi323_gyro_scale, ++ .scale_table_len = ARRAY_SIZE(bmi323_gyro_scale), ++ }, ++}; ++ ++struct bmi323_data { ++ struct device *dev; ++ struct regmap *regmap; ++ struct iio_mount_matrix orientation; ++ enum bmi323_irq_pin irq_pin; ++ struct iio_trigger *trig; ++ bool drdy_trigger_enabled; ++ enum bmi323_state state; ++ s64 fifo_tstamp, old_fifo_tstamp; ++ u32 odrns[BMI323_SENSORS_CNT]; ++ u32 odrhz[BMI323_SENSORS_CNT]; ++ unsigned int feature_events; ++ ++ /* ++ * Lock to protect the members of device's private data from concurrent ++ * access and also to serialize the access of extended registers. ++ * See bmi323_write_ext_reg(..) for more info. ++ */ ++ struct mutex mutex; ++ int watermark; ++ __le16 fifo_buff[BMI323_FIFO_FULL_IN_WORDS] __aligned(IIO_DMA_MINALIGN); ++ struct { ++ __le16 channels[BMI323_CHAN_MAX]; ++ s64 ts __aligned(8); ++ } buffer; ++ __le16 steps_count[BMI323_STEP_LEN]; ++}; ++ ++static const struct iio_mount_matrix * ++bmi323_get_mount_matrix(const struct iio_dev *idev, ++ const struct iio_chan_spec *chan) ++{ ++ struct bmi323_data *data = iio_priv(idev); ++ ++ return &data->orientation; ++} ++ ++static const struct iio_chan_spec_ext_info bmi323_ext_info[] = { ++ IIO_MOUNT_MATRIX(IIO_SHARED_BY_TYPE, bmi323_get_mount_matrix), ++ { } ++}; ++ ++static const struct iio_event_spec bmi323_step_wtrmrk_event = { ++ .type = IIO_EV_TYPE_CHANGE, ++ .dir = IIO_EV_DIR_NONE, ++ .mask_shared_by_type = BIT(IIO_EV_INFO_ENABLE) | ++ BIT(IIO_EV_INFO_VALUE), ++}; ++ ++static const struct iio_event_spec bmi323_accel_event[] = { ++ { ++ .type = IIO_EV_TYPE_MAG, ++ .dir = IIO_EV_DIR_FALLING, ++ .mask_shared_by_type = BIT(IIO_EV_INFO_VALUE) | ++ BIT(IIO_EV_INFO_PERIOD) | ++ BIT(IIO_EV_INFO_HYSTERESIS) | ++ BIT(IIO_EV_INFO_ENABLE), ++ }, ++ { ++ .type = IIO_EV_TYPE_MAG, ++ .dir = IIO_EV_DIR_RISING, ++ .mask_shared_by_type = BIT(IIO_EV_INFO_VALUE) | ++ BIT(IIO_EV_INFO_PERIOD) | ++ BIT(IIO_EV_INFO_HYSTERESIS) | ++ BIT(IIO_EV_INFO_ENABLE), ++ }, ++ { ++ .type = IIO_EV_TYPE_GESTURE, ++ .dir = IIO_EV_DIR_SINGLETAP, ++ .mask_shared_by_type = BIT(IIO_EV_INFO_ENABLE) | ++ BIT(IIO_EV_INFO_VALUE) | ++ BIT(IIO_EV_INFO_RESET_TIMEOUT), ++ }, ++ { ++ .type = IIO_EV_TYPE_GESTURE, ++ .dir = IIO_EV_DIR_DOUBLETAP, ++ .mask_shared_by_type = BIT(IIO_EV_INFO_ENABLE) | ++ BIT(IIO_EV_INFO_VALUE) | ++ BIT(IIO_EV_INFO_RESET_TIMEOUT) | ++ BIT(IIO_EV_INFO_TAP2_MIN_DELAY), ++ }, ++}; ++ ++#define BMI323_ACCEL_CHANNEL(_type, _axis, _index) { \ ++ .type = _type, \ ++ .modified = 1, \ ++ .channel2 = IIO_MOD_##_axis, \ ++ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ ++ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ ++ BIT(IIO_CHAN_INFO_SCALE) | \ ++ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ ++ .info_mask_shared_by_type_available = \ ++ BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ ++ BIT(IIO_CHAN_INFO_SCALE) | \ ++ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ ++ .scan_index = _index, \ ++ .scan_type = { \ ++ .sign = 's', \ ++ .realbits = 16, \ ++ .storagebits = 16, \ ++ .endianness = IIO_LE, \ ++ }, \ ++ .ext_info = bmi323_ext_info, \ ++ .event_spec = bmi323_accel_event, \ ++ .num_event_specs = ARRAY_SIZE(bmi323_accel_event), \ ++} ++ ++#define BMI323_GYRO_CHANNEL(_type, _axis, _index) { \ ++ .type = _type, \ ++ .modified = 1, \ ++ .channel2 = IIO_MOD_##_axis, \ ++ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ ++ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ ++ BIT(IIO_CHAN_INFO_SCALE) | \ ++ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ ++ .info_mask_shared_by_type_available = \ ++ BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ ++ BIT(IIO_CHAN_INFO_SCALE) | \ ++ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ ++ .scan_index = _index, \ ++ .scan_type = { \ ++ .sign = 's', \ ++ .realbits = 16, \ ++ .storagebits = 16, \ ++ .endianness = IIO_LE, \ ++ }, \ ++ .ext_info = bmi323_ext_info, \ ++} ++ ++static const struct iio_chan_spec bmi323_channels[] = { ++ BMI323_ACCEL_CHANNEL(IIO_ACCEL, X, BMI323_ACCEL_X), ++ BMI323_ACCEL_CHANNEL(IIO_ACCEL, Y, BMI323_ACCEL_Y), ++ BMI323_ACCEL_CHANNEL(IIO_ACCEL, Z, BMI323_ACCEL_Z), ++ BMI323_GYRO_CHANNEL(IIO_ANGL_VEL, X, BMI323_GYRO_X), ++ BMI323_GYRO_CHANNEL(IIO_ANGL_VEL, Y, BMI323_GYRO_Y), ++ BMI323_GYRO_CHANNEL(IIO_ANGL_VEL, Z, BMI323_GYRO_Z), ++ { ++ .type = IIO_TEMP, ++ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | ++ BIT(IIO_CHAN_INFO_OFFSET) | ++ BIT(IIO_CHAN_INFO_SCALE), ++ .scan_index = -1, ++ }, ++ { ++ .type = IIO_STEPS, ++ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) | ++ BIT(IIO_CHAN_INFO_ENABLE), ++ .scan_index = -1, ++ .event_spec = &bmi323_step_wtrmrk_event, ++ .num_event_specs = 1, ++ ++ }, ++ IIO_CHAN_SOFT_TIMESTAMP(BMI323_CHAN_MAX), ++}; ++ ++static const int bmi323_acc_gyro_odr[][2] = { ++ { 0, 781250 }, ++ { 1, 562500 }, ++ { 3, 125000 }, ++ { 6, 250000 }, ++ { 12, 500000 }, ++ { 25, 0 }, ++ { 50, 0 }, ++ { 100, 0 }, ++ { 200, 0 }, ++ { 400, 0 }, ++ { 800, 0 }, ++}; ++ ++static const int bmi323_acc_gyro_odrns[] = { ++ 1280 * MEGA, ++ 640 * MEGA, ++ 320 * MEGA, ++ 160 * MEGA, ++ 80 * MEGA, ++ 40 * MEGA, ++ 20 * MEGA, ++ 10 * MEGA, ++ 5 * MEGA, ++ 2500 * KILO, ++ 1250 * KILO, ++}; ++ ++static enum bmi323_sensor_type bmi323_iio_to_sensor(enum iio_chan_type iio_type) ++{ ++ switch (iio_type) { ++ case IIO_ACCEL: ++ return BMI323_ACCEL; ++ case IIO_ANGL_VEL: ++ return BMI323_GYRO; ++ default: ++ return -EINVAL; ++ } ++} ++ ++static int bmi323_set_mode(struct bmi323_data *data, ++ enum bmi323_sensor_type sensor, ++ enum bmi323_opr_mode mode) ++{ ++ guard(mutex)(&data->mutex); ++ return regmap_update_bits(data->regmap, bmi323_hw[sensor].config, ++ BMI323_ACC_GYRO_CONF_MODE_MSK, ++ FIELD_PREP(BMI323_ACC_GYRO_CONF_MODE_MSK, ++ mode)); ++} ++ ++/* ++ * When writing data to extended register there must be no communication to ++ * any other register before write transaction is complete. ++ * See datasheet section 6.2 Extended Register Map Description. ++ */ ++static int bmi323_write_ext_reg(struct bmi323_data *data, unsigned int ext_addr, ++ unsigned int ext_data) ++{ ++ int ret, feature_status; ++ ++ ret = regmap_read(data->regmap, BMI323_FEAT_DATA_STATUS, ++ &feature_status); ++ if (ret) ++ return ret; ++ ++ if (!FIELD_GET(BMI323_FEAT_DATA_TX_RDY_MSK, feature_status)) ++ return -EBUSY; ++ ++ ret = regmap_write(data->regmap, BMI323_FEAT_DATA_ADDR, ext_addr); ++ if (ret) ++ return ret; ++ ++ return regmap_write(data->regmap, BMI323_FEAT_DATA_TX, ext_data); ++} ++ ++/* ++ * When reading data from extended register there must be no communication to ++ * any other register before read transaction is complete. ++ * See datasheet section 6.2 Extended Register Map Description. ++ */ ++static int bmi323_read_ext_reg(struct bmi323_data *data, unsigned int ext_addr, ++ unsigned int *ext_data) ++{ ++ int ret, feature_status; ++ ++ ret = regmap_read(data->regmap, BMI323_FEAT_DATA_STATUS, ++ &feature_status); ++ if (ret) ++ return ret; ++ ++ if (!FIELD_GET(BMI323_FEAT_DATA_TX_RDY_MSK, feature_status)) ++ return -EBUSY; ++ ++ ret = regmap_write(data->regmap, BMI323_FEAT_DATA_ADDR, ext_addr); ++ if (ret) ++ return ret; ++ ++ return regmap_read(data->regmap, BMI323_FEAT_DATA_TX, ext_data); ++} ++ ++static int bmi323_update_ext_reg(struct bmi323_data *data, ++ unsigned int ext_addr, ++ unsigned int mask, unsigned int ext_data) ++{ ++ unsigned int value; ++ int ret; ++ ++ ret = bmi323_read_ext_reg(data, ext_addr, &value); ++ if (ret) ++ return ret; ++ ++ set_mask_bits(&value, mask, ext_data); ++ ++ return bmi323_write_ext_reg(data, ext_addr, value); ++} ++ ++static int bmi323_get_error_status(struct bmi323_data *data) ++{ ++ int error, ret; ++ ++ guard(mutex)(&data->mutex); ++ ret = regmap_read(data->regmap, BMI323_ERR_REG, &error); ++ if (ret) ++ return ret; ++ ++ if (error) ++ dev_err(data->dev, "Sensor error 0x%x\n", error); ++ ++ return error; ++} ++ ++static int bmi323_feature_engine_events(struct bmi323_data *data, ++ const unsigned int event_mask, ++ bool state) ++{ ++ unsigned int value; ++ int ret; ++ ++ ret = regmap_read(data->regmap, BMI323_FEAT_IO0_REG, &value); ++ if (ret) ++ return ret; ++ ++ /* Register must be cleared before changing an active config */ ++ ret = regmap_write(data->regmap, BMI323_FEAT_IO0_REG, 0); ++ if (ret) ++ return ret; ++ ++ if (state) ++ value |= event_mask; ++ else ++ value &= ~event_mask; ++ ++ ret = regmap_write(data->regmap, BMI323_FEAT_IO0_REG, value); ++ if (ret) ++ return ret; ++ ++ return regmap_write(data->regmap, BMI323_FEAT_IO_STATUS_REG, ++ BMI323_FEAT_IO_STATUS_MSK); ++} ++ ++static int bmi323_step_wtrmrk_en(struct bmi323_data *data, int state) ++{ ++ enum bmi323_irq_pin step_irq; ++ int ret; ++ ++ guard(mutex)(&data->mutex); ++ if (!FIELD_GET(BMI323_FEAT_IO0_STP_CNT_MSK, data->feature_events)) ++ return -EINVAL; ++ ++ if (state) ++ step_irq = data->irq_pin; ++ else ++ step_irq = BMI323_IRQ_DISABLED; ++ ++ ret = bmi323_update_ext_reg(data, BMI323_STEP_SC1_REG, ++ BMI323_STEP_SC1_WTRMRK_MSK, ++ FIELD_PREP(BMI323_STEP_SC1_WTRMRK_MSK, ++ state ? 1 : 0)); ++ if (ret) ++ return ret; ++ ++ return regmap_update_bits(data->regmap, BMI323_INT_MAP1_REG, ++ BMI323_STEP_CNT_MSK, ++ FIELD_PREP(BMI323_STEP_CNT_MSK, step_irq)); ++} ++ ++static int bmi323_motion_config_reg(enum iio_event_direction dir) ++{ ++ switch (dir) { ++ case IIO_EV_DIR_RISING: ++ return BMI323_ANYMO1_REG; ++ case IIO_EV_DIR_FALLING: ++ return BMI323_NOMO1_REG; ++ default: ++ return -EINVAL; ++ } ++} ++ ++static int bmi323_motion_event_en(struct bmi323_data *data, ++ enum iio_event_direction dir, int state) ++{ ++ unsigned int state_value = state ? BMI323_FEAT_XYZ_MSK : 0; ++ int config, ret, msk, raw, field_value; ++ enum bmi323_irq_pin motion_irq; ++ int irq_msk, irq_field_val; ++ ++ if (state) ++ motion_irq = data->irq_pin; ++ else ++ motion_irq = BMI323_IRQ_DISABLED; ++ ++ switch (dir) { ++ case IIO_EV_DIR_RISING: ++ msk = BMI323_FEAT_IO0_XYZ_MOTION_MSK; ++ raw = 512; ++ config = BMI323_ANYMO1_REG; ++ irq_msk = BMI323_MOTION_MSK; ++ irq_field_val = FIELD_PREP(BMI323_MOTION_MSK, motion_irq); ++ field_value = FIELD_PREP(BMI323_FEAT_IO0_XYZ_MOTION_MSK, ++ state_value); ++ break; ++ case IIO_EV_DIR_FALLING: ++ msk = BMI323_FEAT_IO0_XYZ_NOMOTION_MSK; ++ raw = 0; ++ config = BMI323_NOMO1_REG; ++ irq_msk = BMI323_NOMOTION_MSK; ++ irq_field_val = FIELD_PREP(BMI323_NOMOTION_MSK, motion_irq); ++ field_value = FIELD_PREP(BMI323_FEAT_IO0_XYZ_NOMOTION_MSK, ++ state_value); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ guard(mutex)(&data->mutex); ++ ret = bmi323_feature_engine_events(data, msk, state); ++ if (ret) ++ return ret; ++ ++ ret = bmi323_update_ext_reg(data, config, ++ BMI323_MO1_REF_UP_MSK, ++ FIELD_PREP(BMI323_MO1_REF_UP_MSK, 0)); ++ if (ret) ++ return ret; ++ ++ /* Set initial value to avoid interrupts while enabling*/ ++ ret = bmi323_update_ext_reg(data, config, ++ BMI323_MO1_SLOPE_TH_MSK, ++ FIELD_PREP(BMI323_MO1_SLOPE_TH_MSK, raw)); ++ if (ret) ++ return ret; ++ ++ ret = regmap_update_bits(data->regmap, BMI323_INT_MAP1_REG, irq_msk, ++ irq_field_val); ++ if (ret) ++ return ret; ++ ++ set_mask_bits(&data->feature_events, msk, field_value); ++ ++ return 0; ++} ++ ++static int bmi323_tap_event_en(struct bmi323_data *data, ++ enum iio_event_direction dir, int state) ++{ ++ enum bmi323_irq_pin tap_irq; ++ int ret, tap_enabled; ++ ++ guard(mutex)(&data->mutex); ++ ++ if (data->odrhz[BMI323_ACCEL] < 200) { ++ dev_err(data->dev, "Invalid accelrometer parameter\n"); ++ return -EINVAL; ++ } ++ ++ switch (dir) { ++ case IIO_EV_DIR_SINGLETAP: ++ ret = bmi323_feature_engine_events(data, ++ BMI323_FEAT_IO0_S_TAP_MSK, ++ state); ++ if (ret) ++ return ret; ++ ++ set_mask_bits(&data->feature_events, BMI323_FEAT_IO0_S_TAP_MSK, ++ FIELD_PREP(BMI323_FEAT_IO0_S_TAP_MSK, state)); ++ break; ++ case IIO_EV_DIR_DOUBLETAP: ++ ret = bmi323_feature_engine_events(data, ++ BMI323_FEAT_IO0_D_TAP_MSK, ++ state); ++ if (ret) ++ return ret; ++ ++ set_mask_bits(&data->feature_events, BMI323_FEAT_IO0_D_TAP_MSK, ++ FIELD_PREP(BMI323_FEAT_IO0_D_TAP_MSK, state)); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ tap_enabled = FIELD_GET(BMI323_FEAT_IO0_S_TAP_MSK | ++ BMI323_FEAT_IO0_D_TAP_MSK, ++ data->feature_events); ++ ++ if (tap_enabled) ++ tap_irq = data->irq_pin; ++ else ++ tap_irq = BMI323_IRQ_DISABLED; ++ ++ ret = regmap_update_bits(data->regmap, BMI323_INT_MAP2_REG, ++ BMI323_TAP_MSK, ++ FIELD_PREP(BMI323_TAP_MSK, tap_irq)); ++ if (ret) ++ return ret; ++ ++ if (!state) ++ return 0; ++ ++ ret = bmi323_update_ext_reg(data, BMI323_TAP1_REG, ++ BMI323_TAP1_MAX_PEAKS_MSK, ++ FIELD_PREP(BMI323_TAP1_MAX_PEAKS_MSK, ++ 0x04)); ++ if (ret) ++ return ret; ++ ++ ret = bmi323_update_ext_reg(data, BMI323_TAP1_REG, ++ BMI323_TAP1_AXIS_SEL_MSK, ++ FIELD_PREP(BMI323_TAP1_AXIS_SEL_MSK, ++ BMI323_AXIS_XYZ_MSK)); ++ if (ret) ++ return ret; ++ ++ return bmi323_update_ext_reg(data, BMI323_TAP1_REG, ++ BMI323_TAP1_TIMOUT_MSK, ++ FIELD_PREP(BMI323_TAP1_TIMOUT_MSK, ++ 0)); ++} ++ ++static ssize_t in_accel_gesture_tap_wait_dur_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ struct iio_dev *indio_dev = dev_to_iio_dev(dev); ++ struct bmi323_data *data = iio_priv(indio_dev); ++ unsigned int reg_value, raw; ++ int ret, val[2]; ++ ++ scoped_guard(mutex, &data->mutex) { ++ ret = bmi323_read_ext_reg(data, BMI323_TAP2_REG, ®_value); ++ if (ret) ++ return ret; ++ } ++ ++ raw = FIELD_GET(BMI323_TAP2_MAX_DUR_MSK, reg_value); ++ val[0] = raw / BMI323_MAX_GES_DUR_SCALE; ++ val[1] = BMI323_RAW_TO_MICRO(raw, BMI323_MAX_GES_DUR_SCALE); ++ ++ return iio_format_value(buf, IIO_VAL_INT_PLUS_MICRO, ARRAY_SIZE(val), ++ val); ++} ++ ++static ssize_t in_accel_gesture_tap_wait_dur_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t len) ++{ ++ struct iio_dev *indio_dev = dev_to_iio_dev(dev); ++ struct bmi323_data *data = iio_priv(indio_dev); ++ int ret, val_int, val_fract, raw; ++ ++ ret = iio_str_to_fixpoint(buf, 100000, &val_int, &val_fract); ++ if (ret) ++ return ret; ++ ++ raw = BMI323_INT_MICRO_TO_RAW(val_int, val_fract, ++ BMI323_MAX_GES_DUR_SCALE); ++ if (!in_range(raw, 0, 64)) ++ return -EINVAL; ++ ++ guard(mutex)(&data->mutex); ++ ret = bmi323_update_ext_reg(data, BMI323_TAP2_REG, ++ BMI323_TAP2_MAX_DUR_MSK, ++ FIELD_PREP(BMI323_TAP2_MAX_DUR_MSK, raw)); ++ if (ret) ++ return ret; ++ ++ return len; ++} ++ ++/* ++ * Maximum duration from first tap within the second tap is expected to happen. ++ * This timeout is applicable only if gesture_tap_wait_timeout is enabled. ++ */ ++static IIO_DEVICE_ATTR_RW(in_accel_gesture_tap_wait_dur, 0); ++ ++static ssize_t in_accel_gesture_tap_wait_timeout_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ struct iio_dev *indio_dev = dev_to_iio_dev(dev); ++ struct bmi323_data *data = iio_priv(indio_dev); ++ unsigned int reg_value, raw; ++ int ret; ++ ++ scoped_guard(mutex, &data->mutex) { ++ ret = bmi323_read_ext_reg(data, BMI323_TAP1_REG, ®_value); ++ if (ret) ++ return ret; ++ } ++ ++ raw = FIELD_GET(BMI323_TAP1_TIMOUT_MSK, reg_value); ++ ++ return iio_format_value(buf, IIO_VAL_INT, 1, &raw); ++} ++ ++static ssize_t in_accel_gesture_tap_wait_timeout_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, ++ size_t len) ++{ ++ struct iio_dev *indio_dev = dev_to_iio_dev(dev); ++ struct bmi323_data *data = iio_priv(indio_dev); ++ bool val; ++ int ret; ++ ++ ret = kstrtobool(buf, &val); ++ if (ret) ++ return ret; ++ ++ guard(mutex)(&data->mutex); ++ ret = bmi323_update_ext_reg(data, BMI323_TAP1_REG, ++ BMI323_TAP1_TIMOUT_MSK, ++ FIELD_PREP(BMI323_TAP1_TIMOUT_MSK, val)); ++ if (ret) ++ return ret; ++ ++ return len; ++} ++ ++/* Enable/disable gesture confirmation with wait time */ ++static IIO_DEVICE_ATTR_RW(in_accel_gesture_tap_wait_timeout, 0); ++ ++static IIO_CONST_ATTR(in_accel_gesture_tap_wait_dur_available, ++ "[0.0 0.04 2.52]"); ++ ++static IIO_CONST_ATTR(in_accel_gesture_doubletap_tap2_min_delay_available, ++ "[0.005 0.005 0.075]"); ++ ++static IIO_CONST_ATTR(in_accel_gesture_tap_reset_timeout_available, ++ "[0.04 0.04 0.6]"); ++ ++static IIO_CONST_ATTR(in_accel_gesture_tap_value_available, "[0.0 0.002 1.99]"); ++ ++static IIO_CONST_ATTR(in_accel_mag_value_available, "[0.0 0.002 7.99]"); ++ ++static IIO_CONST_ATTR(in_accel_mag_period_available, "[0.0 0.02 162.0]"); ++ ++static IIO_CONST_ATTR(in_accel_mag_hysteresis_available, "[0.0 0.002 1.99]"); ++ ++static struct attribute *bmi323_event_attributes[] = { ++ &iio_const_attr_in_accel_gesture_tap_value_available.dev_attr.attr, ++ &iio_const_attr_in_accel_gesture_tap_reset_timeout_available.dev_attr.attr, ++ &iio_const_attr_in_accel_gesture_doubletap_tap2_min_delay_available.dev_attr.attr, ++ &iio_const_attr_in_accel_gesture_tap_wait_dur_available.dev_attr.attr, ++ &iio_dev_attr_in_accel_gesture_tap_wait_timeout.dev_attr.attr, ++ &iio_dev_attr_in_accel_gesture_tap_wait_dur.dev_attr.attr, ++ &iio_const_attr_in_accel_mag_value_available.dev_attr.attr, ++ &iio_const_attr_in_accel_mag_period_available.dev_attr.attr, ++ &iio_const_attr_in_accel_mag_hysteresis_available.dev_attr.attr, ++ NULL ++}; ++ ++static const struct attribute_group bmi323_event_attribute_group = { ++ .attrs = bmi323_event_attributes, ++}; ++ ++static int bmi323_write_event_config(struct iio_dev *indio_dev, ++ const struct iio_chan_spec *chan, ++ enum iio_event_type type, ++ enum iio_event_direction dir, int state) ++{ ++ struct bmi323_data *data = iio_priv(indio_dev); ++ ++ switch (type) { ++ case IIO_EV_TYPE_MAG: ++ return bmi323_motion_event_en(data, dir, state); ++ case IIO_EV_TYPE_GESTURE: ++ return bmi323_tap_event_en(data, dir, state); ++ case IIO_EV_TYPE_CHANGE: ++ return bmi323_step_wtrmrk_en(data, state); ++ default: ++ return -EINVAL; ++ } ++} ++ ++static int bmi323_read_event_config(struct iio_dev *indio_dev, ++ const struct iio_chan_spec *chan, ++ enum iio_event_type type, ++ enum iio_event_direction dir) ++{ ++ struct bmi323_data *data = iio_priv(indio_dev); ++ int ret, value, reg_val; ++ ++ guard(mutex)(&data->mutex); ++ ++ switch (chan->type) { ++ case IIO_ACCEL: ++ switch (dir) { ++ case IIO_EV_DIR_SINGLETAP: ++ ret = FIELD_GET(BMI323_FEAT_IO0_S_TAP_MSK, ++ data->feature_events); ++ break; ++ case IIO_EV_DIR_DOUBLETAP: ++ ret = FIELD_GET(BMI323_FEAT_IO0_D_TAP_MSK, ++ data->feature_events); ++ break; ++ case IIO_EV_DIR_RISING: ++ value = FIELD_GET(BMI323_FEAT_IO0_XYZ_MOTION_MSK, ++ data->feature_events); ++ ret = value ? 1 : 0; ++ break; ++ case IIO_EV_DIR_FALLING: ++ value = FIELD_GET(BMI323_FEAT_IO0_XYZ_NOMOTION_MSK, ++ data->feature_events); ++ ret = value ? 1 : 0; ++ break; ++ default: ++ ret = -EINVAL; ++ break; ++ } ++ return ret; ++ case IIO_STEPS: ++ ret = regmap_read(data->regmap, BMI323_INT_MAP1_REG, ®_val); ++ if (ret) ++ return ret; ++ ++ return FIELD_GET(BMI323_STEP_CNT_MSK, reg_val) ? 1 : 0; ++ default: ++ return -EINVAL; ++ } ++} ++ ++static int bmi323_write_event_value(struct iio_dev *indio_dev, ++ const struct iio_chan_spec *chan, ++ enum iio_event_type type, ++ enum iio_event_direction dir, ++ enum iio_event_info info, ++ int val, int val2) ++{ ++ struct bmi323_data *data = iio_priv(indio_dev); ++ unsigned int raw; ++ int reg; ++ ++ guard(mutex)(&data->mutex); ++ ++ switch (type) { ++ case IIO_EV_TYPE_GESTURE: ++ switch (info) { ++ case IIO_EV_INFO_VALUE: ++ if (!in_range(val, 0, 2)) ++ return -EINVAL; ++ ++ raw = BMI323_INT_MICRO_TO_RAW(val, val2, ++ BMI323_TAP_THRES_SCALE); ++ ++ return bmi323_update_ext_reg(data, BMI323_TAP2_REG, ++ BMI323_TAP2_THRES_MSK, ++ FIELD_PREP(BMI323_TAP2_THRES_MSK, ++ raw)); ++ case IIO_EV_INFO_RESET_TIMEOUT: ++ if (val || !in_range(val2, 40000, 560001)) ++ return -EINVAL; ++ ++ raw = BMI323_INT_MICRO_TO_RAW(val, val2, ++ BMI323_QUITE_TIM_GES_SCALE); ++ ++ return bmi323_update_ext_reg(data, BMI323_TAP3_REG, ++ BMI323_TAP3_QT_AFT_GES_MSK, ++ FIELD_PREP(BMI323_TAP3_QT_AFT_GES_MSK, ++ raw)); ++ case IIO_EV_INFO_TAP2_MIN_DELAY: ++ if (val || !in_range(val2, 5000, 70001)) ++ return -EINVAL; ++ ++ raw = BMI323_INT_MICRO_TO_RAW(val, val2, ++ BMI323_DUR_BW_TAP_SCALE); ++ ++ return bmi323_update_ext_reg(data, BMI323_TAP3_REG, ++ BMI323_TAP3_QT_BW_TAP_MSK, ++ FIELD_PREP(BMI323_TAP3_QT_BW_TAP_MSK, ++ raw)); ++ default: ++ return -EINVAL; ++ } ++ case IIO_EV_TYPE_MAG: ++ reg = bmi323_motion_config_reg(dir); ++ if (reg < 0) ++ return -EINVAL; ++ ++ switch (info) { ++ case IIO_EV_INFO_VALUE: ++ if (!in_range(val, 0, 8)) ++ return -EINVAL; ++ ++ raw = BMI323_INT_MICRO_TO_RAW(val, val2, ++ BMI323_MOTION_THRES_SCALE); ++ ++ return bmi323_update_ext_reg(data, reg, ++ BMI323_MO1_SLOPE_TH_MSK, ++ FIELD_PREP(BMI323_MO1_SLOPE_TH_MSK, ++ raw)); ++ case IIO_EV_INFO_PERIOD: ++ if (!in_range(val, 0, 163)) ++ return -EINVAL; ++ ++ raw = BMI323_INT_MICRO_TO_RAW(val, val2, ++ BMI323_MOTION_DURAT_SCALE); ++ ++ return bmi323_update_ext_reg(data, ++ reg + BMI323_MO3_OFFSET, ++ BMI323_MO3_DURA_MSK, ++ FIELD_PREP(BMI323_MO3_DURA_MSK, ++ raw)); ++ case IIO_EV_INFO_HYSTERESIS: ++ if (!in_range(val, 0, 2)) ++ return -EINVAL; ++ ++ raw = BMI323_INT_MICRO_TO_RAW(val, val2, ++ BMI323_MOTION_HYSTR_SCALE); ++ ++ return bmi323_update_ext_reg(data, ++ reg + BMI323_MO2_OFFSET, ++ BMI323_MO2_HYSTR_MSK, ++ FIELD_PREP(BMI323_MO2_HYSTR_MSK, ++ raw)); ++ default: ++ return -EINVAL; ++ } ++ case IIO_EV_TYPE_CHANGE: ++ if (!in_range(val, 0, 20461)) ++ return -EINVAL; ++ ++ raw = val / 20; ++ return bmi323_update_ext_reg(data, BMI323_STEP_SC1_REG, ++ BMI323_STEP_SC1_WTRMRK_MSK, ++ FIELD_PREP(BMI323_STEP_SC1_WTRMRK_MSK, ++ raw)); ++ default: ++ return -EINVAL; ++ } ++} ++ ++static int bmi323_read_event_value(struct iio_dev *indio_dev, ++ const struct iio_chan_spec *chan, ++ enum iio_event_type type, ++ enum iio_event_direction dir, ++ enum iio_event_info info, ++ int *val, int *val2) ++{ ++ struct bmi323_data *data = iio_priv(indio_dev); ++ unsigned int raw, reg_value; ++ int ret, reg; ++ ++ guard(mutex)(&data->mutex); ++ ++ switch (type) { ++ case IIO_EV_TYPE_GESTURE: ++ switch (info) { ++ case IIO_EV_INFO_VALUE: ++ ret = bmi323_read_ext_reg(data, BMI323_TAP2_REG, ++ ®_value); ++ if (ret) ++ return ret; ++ ++ raw = FIELD_GET(BMI323_TAP2_THRES_MSK, reg_value); ++ *val = raw / BMI323_TAP_THRES_SCALE; ++ *val2 = BMI323_RAW_TO_MICRO(raw, BMI323_TAP_THRES_SCALE); ++ return IIO_VAL_INT_PLUS_MICRO; ++ case IIO_EV_INFO_RESET_TIMEOUT: ++ ret = bmi323_read_ext_reg(data, BMI323_TAP3_REG, ++ ®_value); ++ if (ret) ++ return ret; ++ ++ raw = FIELD_GET(BMI323_TAP3_QT_AFT_GES_MSK, reg_value); ++ *val = 0; ++ *val2 = BMI323_RAW_TO_MICRO(raw, ++ BMI323_QUITE_TIM_GES_SCALE); ++ return IIO_VAL_INT_PLUS_MICRO; ++ case IIO_EV_INFO_TAP2_MIN_DELAY: ++ ret = bmi323_read_ext_reg(data, BMI323_TAP3_REG, ++ ®_value); ++ if (ret) ++ return ret; ++ ++ raw = FIELD_GET(BMI323_TAP3_QT_BW_TAP_MSK, reg_value); ++ *val = 0; ++ *val2 = BMI323_RAW_TO_MICRO(raw, ++ BMI323_DUR_BW_TAP_SCALE); ++ return IIO_VAL_INT_PLUS_MICRO; ++ default: ++ return -EINVAL; ++ } ++ case IIO_EV_TYPE_MAG: ++ reg = bmi323_motion_config_reg(dir); ++ if (reg < 0) ++ return -EINVAL; ++ ++ switch (info) { ++ case IIO_EV_INFO_VALUE: ++ ret = bmi323_read_ext_reg(data, reg, ®_value); ++ if (ret) ++ return ret; ++ ++ raw = FIELD_GET(BMI323_MO1_SLOPE_TH_MSK, reg_value); ++ *val = raw / BMI323_MOTION_THRES_SCALE; ++ *val2 = BMI323_RAW_TO_MICRO(raw, ++ BMI323_MOTION_THRES_SCALE); ++ return IIO_VAL_INT_PLUS_MICRO; ++ case IIO_EV_INFO_PERIOD: ++ ret = bmi323_read_ext_reg(data, ++ reg + BMI323_MO3_OFFSET, ++ ®_value); ++ if (ret) ++ return ret; ++ ++ raw = FIELD_GET(BMI323_MO3_DURA_MSK, reg_value); ++ *val = raw / BMI323_MOTION_DURAT_SCALE; ++ *val2 = BMI323_RAW_TO_MICRO(raw, ++ BMI323_MOTION_DURAT_SCALE); ++ return IIO_VAL_INT_PLUS_MICRO; ++ case IIO_EV_INFO_HYSTERESIS: ++ ret = bmi323_read_ext_reg(data, ++ reg + BMI323_MO2_OFFSET, ++ ®_value); ++ if (ret) ++ return ret; ++ ++ raw = FIELD_GET(BMI323_MO2_HYSTR_MSK, reg_value); ++ *val = raw / BMI323_MOTION_HYSTR_SCALE; ++ *val2 = BMI323_RAW_TO_MICRO(raw, ++ BMI323_MOTION_HYSTR_SCALE); ++ return IIO_VAL_INT_PLUS_MICRO; ++ default: ++ return -EINVAL; ++ } ++ case IIO_EV_TYPE_CHANGE: ++ ret = bmi323_read_ext_reg(data, BMI323_STEP_SC1_REG, ++ ®_value); ++ if (ret) ++ return ret; ++ ++ raw = FIELD_GET(BMI323_STEP_SC1_WTRMRK_MSK, reg_value); ++ *val = raw * 20; ++ return IIO_VAL_INT; ++ default: ++ return -EINVAL; ++ } ++} ++ ++static int __bmi323_fifo_flush(struct iio_dev *indio_dev) ++{ ++ struct bmi323_data *data = iio_priv(indio_dev); ++ int i, ret, fifo_lvl, frame_count, bit, index; ++ __le16 *frame, *pchannels; ++ u64 sample_period; ++ s64 tstamp; ++ ++ guard(mutex)(&data->mutex); ++ ret = regmap_read(data->regmap, BMI323_FIFO_FILL_LEVEL_REG, &fifo_lvl); ++ if (ret) ++ return ret; ++ ++ fifo_lvl = min(fifo_lvl, BMI323_FIFO_FULL_IN_WORDS); ++ ++ frame_count = fifo_lvl / BMI323_FIFO_FRAME_LENGTH; ++ if (!frame_count) ++ return -EINVAL; ++ ++ if (fifo_lvl % BMI323_FIFO_FRAME_LENGTH) ++ dev_warn(data->dev, "Bad FIFO alignment\n"); ++ ++ /* ++ * Approximate timestamps for each of the sample based on the sampling ++ * frequency, timestamp for last sample and number of samples. ++ */ ++ if (data->old_fifo_tstamp) { ++ sample_period = data->fifo_tstamp - data->old_fifo_tstamp; ++ do_div(sample_period, frame_count); ++ } else { ++ sample_period = data->odrns[BMI323_ACCEL]; ++ } ++ ++ tstamp = data->fifo_tstamp - (frame_count - 1) * sample_period; ++ ++ ret = regmap_noinc_read(data->regmap, BMI323_FIFO_DATA_REG, ++ &data->fifo_buff[0], ++ fifo_lvl * BMI323_BYTES_PER_SAMPLE); ++ if (ret) ++ return ret; ++ ++ for (i = 0; i < frame_count; i++) { ++ frame = &data->fifo_buff[i * BMI323_FIFO_FRAME_LENGTH]; ++ pchannels = &data->buffer.channels[0]; ++ ++ index = 0; ++ for_each_set_bit(bit, indio_dev->active_scan_mask, ++ BMI323_CHAN_MAX) ++ pchannels[index++] = frame[bit]; ++ ++ iio_push_to_buffers_with_timestamp(indio_dev, &data->buffer, ++ tstamp); ++ ++ tstamp += sample_period; ++ } ++ ++ return frame_count; ++} ++ ++static int bmi323_set_watermark(struct iio_dev *indio_dev, unsigned int val) ++{ ++ struct bmi323_data *data = iio_priv(indio_dev); ++ ++ val = min(val, (u32)BMI323_FIFO_FULL_IN_FRAMES); ++ ++ guard(mutex)(&data->mutex); ++ data->watermark = val; ++ ++ return 0; ++} ++ ++static int bmi323_fifo_disable(struct bmi323_data *data) ++{ ++ int ret; ++ ++ guard(mutex)(&data->mutex); ++ ret = regmap_write(data->regmap, BMI323_FIFO_CONF_REG, 0); ++ if (ret) ++ return ret; ++ ++ ret = regmap_update_bits(data->regmap, BMI323_INT_MAP2_REG, ++ BMI323_FIFO_WTRMRK_MSK, ++ FIELD_PREP(BMI323_FIFO_WTRMRK_MSK, 0)); ++ if (ret) ++ return ret; ++ ++ data->fifo_tstamp = 0; ++ data->state = BMI323_IDLE; ++ ++ return 0; ++} ++ ++static int bmi323_buffer_predisable(struct iio_dev *indio_dev) ++{ ++ struct bmi323_data *data = iio_priv(indio_dev); ++ ++ if (iio_device_get_current_mode(indio_dev) == INDIO_BUFFER_TRIGGERED) ++ return 0; ++ ++ return bmi323_fifo_disable(data); ++} ++ ++static int bmi323_update_watermark(struct bmi323_data *data) ++{ ++ int wtrmrk; ++ ++ wtrmrk = data->watermark * BMI323_FIFO_FRAME_LENGTH; ++ ++ return regmap_write(data->regmap, BMI323_FIFO_WTRMRK_REG, wtrmrk); ++} ++ ++static int bmi323_fifo_enable(struct bmi323_data *data) ++{ ++ int ret; ++ ++ guard(mutex)(&data->mutex); ++ ret = regmap_update_bits(data->regmap, BMI323_FIFO_CONF_REG, ++ BMI323_FIFO_CONF_ACC_GYR_EN_MSK, ++ FIELD_PREP(BMI323_FIFO_CONF_ACC_GYR_EN_MSK, ++ BMI323_FIFO_ACC_GYR_MSK)); ++ if (ret) ++ return ret; ++ ++ ret = regmap_update_bits(data->regmap, BMI323_INT_MAP2_REG, ++ BMI323_FIFO_WTRMRK_MSK, ++ FIELD_PREP(BMI323_FIFO_WTRMRK_MSK, ++ data->irq_pin)); ++ if (ret) ++ return ret; ++ ++ ret = bmi323_update_watermark(data); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write(data->regmap, BMI323_FIFO_CTRL_REG, ++ BMI323_FIFO_FLUSH_MSK); ++ if (ret) ++ return ret; ++ ++ data->state = BMI323_BUFFER_FIFO; ++ ++ return 0; ++} ++ ++static int bmi323_buffer_preenable(struct iio_dev *indio_dev) ++{ ++ struct bmi323_data *data = iio_priv(indio_dev); ++ ++ guard(mutex)(&data->mutex); ++ /* ++ * When the ODR of the accelerometer and gyroscope do not match, the ++ * maximum ODR value between the accelerometer and gyroscope is used ++ * for FIFO and the signal with lower ODR will insert dummy frame. ++ * So allow buffer read only when ODR's of accelero and gyro are equal. ++ * See datasheet section 5.7 "FIFO Data Buffering". ++ */ ++ if (data->odrns[BMI323_ACCEL] != data->odrns[BMI323_GYRO]) { ++ dev_err(data->dev, "Accelero and Gyro ODR doesn't match\n"); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int bmi323_buffer_postenable(struct iio_dev *indio_dev) ++{ ++ struct bmi323_data *data = iio_priv(indio_dev); ++ ++ if (iio_device_get_current_mode(indio_dev) == INDIO_BUFFER_TRIGGERED) ++ return 0; ++ ++ return bmi323_fifo_enable(data); ++} ++ ++static ssize_t hwfifo_watermark_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct iio_dev *indio_dev = dev_to_iio_dev(dev); ++ struct bmi323_data *data = iio_priv(indio_dev); ++ int wm; ++ ++ scoped_guard(mutex, &data->mutex) ++ wm = data->watermark; ++ ++ return sysfs_emit(buf, "%d\n", wm); ++} ++static IIO_DEVICE_ATTR_RO(hwfifo_watermark, 0); ++ ++static ssize_t hwfifo_enabled_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ struct iio_dev *indio_dev = dev_to_iio_dev(dev); ++ struct bmi323_data *data = iio_priv(indio_dev); ++ bool state; ++ ++ scoped_guard(mutex, &data->mutex) ++ state = data->state == BMI323_BUFFER_FIFO; ++ ++ return sysfs_emit(buf, "%d\n", state); ++} ++static IIO_DEVICE_ATTR_RO(hwfifo_enabled, 0); ++ ++static const struct iio_dev_attr *bmi323_fifo_attributes[] = { ++ &iio_dev_attr_hwfifo_watermark, ++ &iio_dev_attr_hwfifo_enabled, ++ NULL ++}; ++ ++static const struct iio_buffer_setup_ops bmi323_buffer_ops = { ++ .preenable = bmi323_buffer_preenable, ++ .postenable = bmi323_buffer_postenable, ++ .predisable = bmi323_buffer_predisable, ++}; ++ ++static irqreturn_t bmi323_irq_thread_handler(int irq, void *private) ++{ ++ struct iio_dev *indio_dev = private; ++ struct bmi323_data *data = iio_priv(indio_dev); ++ unsigned int status_addr, status, feature_event; ++ s64 timestamp = iio_get_time_ns(indio_dev); ++ int ret; ++ ++ if (data->irq_pin == BMI323_IRQ_INT1) ++ status_addr = BMI323_STATUS_INT1_REG; ++ else ++ status_addr = BMI323_STATUS_INT2_REG; ++ ++ scoped_guard(mutex, &data->mutex) { ++ ret = regmap_read(data->regmap, status_addr, &status); ++ if (ret) ++ return IRQ_NONE; ++ } ++ ++ if (!status || FIELD_GET(BMI323_STATUS_ERROR_MSK, status)) ++ return IRQ_NONE; ++ ++ if (FIELD_GET(BMI323_STATUS_FIFO_WTRMRK_MSK, status)) { ++ data->old_fifo_tstamp = data->fifo_tstamp; ++ data->fifo_tstamp = iio_get_time_ns(indio_dev); ++ ret = __bmi323_fifo_flush(indio_dev); ++ if (ret < 0) ++ return IRQ_NONE; ++ } ++ ++ if (FIELD_GET(BMI323_STATUS_ACC_GYR_DRDY_MSK, status)) ++ iio_trigger_poll_nested(data->trig); ++ ++ if (FIELD_GET(BMI323_STATUS_MOTION_MSK, status)) ++ iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, ++ IIO_MOD_X_OR_Y_OR_Z, ++ IIO_EV_TYPE_MAG, ++ IIO_EV_DIR_RISING), ++ timestamp); ++ ++ if (FIELD_GET(BMI323_STATUS_NOMOTION_MSK, status)) ++ iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, ++ IIO_MOD_X_OR_Y_OR_Z, ++ IIO_EV_TYPE_MAG, ++ IIO_EV_DIR_FALLING), ++ timestamp); ++ ++ if (FIELD_GET(BMI323_STATUS_STP_WTR_MSK, status)) ++ iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_STEPS, 0, ++ IIO_NO_MOD, ++ IIO_EV_TYPE_CHANGE, ++ IIO_EV_DIR_NONE), ++ timestamp); ++ ++ if (FIELD_GET(BMI323_STATUS_TAP_MSK, status)) { ++ scoped_guard(mutex, &data->mutex) { ++ ret = regmap_read(data->regmap, ++ BMI323_FEAT_EVNT_EXT_REG, ++ &feature_event); ++ if (ret) ++ return IRQ_NONE; ++ } ++ ++ if (FIELD_GET(BMI323_FEAT_EVNT_EXT_S_MSK, feature_event)) { ++ iio_push_event(indio_dev, ++ IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, ++ IIO_MOD_X_OR_Y_OR_Z, ++ IIO_EV_TYPE_GESTURE, ++ IIO_EV_DIR_SINGLETAP), ++ timestamp); ++ } ++ ++ if (FIELD_GET(BMI323_FEAT_EVNT_EXT_D_MSK, feature_event)) ++ iio_push_event(indio_dev, ++ IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, ++ IIO_MOD_X_OR_Y_OR_Z, ++ IIO_EV_TYPE_GESTURE, ++ IIO_EV_DIR_DOUBLETAP), ++ timestamp); ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++static int bmi323_set_drdy_irq(struct bmi323_data *data, ++ enum bmi323_irq_pin irq_pin) ++{ ++ int ret; ++ ++ ret = regmap_update_bits(data->regmap, BMI323_INT_MAP2_REG, ++ BMI323_GYR_DRDY_MSK, ++ FIELD_PREP(BMI323_GYR_DRDY_MSK, irq_pin)); ++ if (ret) ++ return ret; ++ ++ return regmap_update_bits(data->regmap, BMI323_INT_MAP2_REG, ++ BMI323_ACC_DRDY_MSK, ++ FIELD_PREP(BMI323_ACC_DRDY_MSK, irq_pin)); ++} ++ ++static int bmi323_data_rdy_trigger_set_state(struct iio_trigger *trig, ++ bool state) ++{ ++ struct bmi323_data *data = iio_trigger_get_drvdata(trig); ++ enum bmi323_irq_pin irq_pin; ++ ++ guard(mutex)(&data->mutex); ++ ++ if (data->state == BMI323_BUFFER_FIFO) { ++ dev_warn(data->dev, "Can't set trigger when FIFO enabled\n"); ++ return -EBUSY; ++ } ++ ++ if (state) { ++ data->state = BMI323_BUFFER_DRDY_TRIGGERED; ++ irq_pin = data->irq_pin; ++ } else { ++ data->state = BMI323_IDLE; ++ irq_pin = BMI323_IRQ_DISABLED; ++ } ++ ++ return bmi323_set_drdy_irq(data, irq_pin); ++} ++ ++static const struct iio_trigger_ops bmi323_trigger_ops = { ++ .set_trigger_state = &bmi323_data_rdy_trigger_set_state, ++}; ++ ++static irqreturn_t bmi323_trigger_handler(int irq, void *p) ++{ ++ struct iio_poll_func *pf = p; ++ struct iio_dev *indio_dev = pf->indio_dev; ++ struct bmi323_data *data = iio_priv(indio_dev); ++ int ret, bit, index = 0; ++ ++ /* Lock to protect the data->buffer */ ++ guard(mutex)(&data->mutex); ++ ++ if (*indio_dev->active_scan_mask == BMI323_ALL_CHAN_MSK) { ++ ret = regmap_bulk_read(data->regmap, BMI323_ACCEL_X_REG, ++ &data->buffer.channels, ++ ARRAY_SIZE(data->buffer.channels)); ++ if (ret) ++ return IRQ_NONE; ++ } else { ++ for_each_set_bit(bit, indio_dev->active_scan_mask, ++ BMI323_CHAN_MAX) { ++ ret = regmap_raw_read(data->regmap, ++ BMI323_ACCEL_X_REG + bit, ++ &data->buffer.channels[index++], ++ BMI323_BYTES_PER_SAMPLE); ++ if (ret) ++ return IRQ_NONE; ++ } ++ } ++ ++ iio_push_to_buffers_with_timestamp(indio_dev, &data->buffer, ++ iio_get_time_ns(indio_dev)); ++ ++ iio_trigger_notify_done(indio_dev->trig); ++ ++ return IRQ_HANDLED; ++} ++ ++static int bmi323_set_average(struct bmi323_data *data, ++ enum bmi323_sensor_type sensor, int avg) ++{ ++ int raw = ARRAY_SIZE(bmi323_accel_gyro_avrg); ++ ++ while (raw--) ++ if (avg == bmi323_accel_gyro_avrg[raw]) ++ break; ++ if (raw < 0) ++ return -EINVAL; ++ ++ guard(mutex)(&data->mutex); ++ return regmap_update_bits(data->regmap, bmi323_hw[sensor].config, ++ BMI323_ACC_GYRO_CONF_AVG_MSK, ++ FIELD_PREP(BMI323_ACC_GYRO_CONF_AVG_MSK, ++ raw)); ++} ++ ++static int bmi323_get_average(struct bmi323_data *data, ++ enum bmi323_sensor_type sensor, int *avg) ++{ ++ int ret, value, raw; ++ ++ scoped_guard(mutex, &data->mutex) { ++ ret = regmap_read(data->regmap, bmi323_hw[sensor].config, &value); ++ if (ret) ++ return ret; ++ } ++ ++ raw = FIELD_GET(BMI323_ACC_GYRO_CONF_AVG_MSK, value); ++ *avg = bmi323_accel_gyro_avrg[raw]; ++ ++ return IIO_VAL_INT; ++} ++ ++static int bmi323_enable_steps(struct bmi323_data *data, int val) ++{ ++ int ret; ++ ++ guard(mutex)(&data->mutex); ++ if (data->odrhz[BMI323_ACCEL] < 200) { ++ dev_err(data->dev, "Invalid accelrometer parameter\n"); ++ return -EINVAL; ++ } ++ ++ ret = bmi323_feature_engine_events(data, BMI323_FEAT_IO0_STP_CNT_MSK, ++ val ? 1 : 0); ++ if (ret) ++ return ret; ++ ++ set_mask_bits(&data->feature_events, BMI323_FEAT_IO0_STP_CNT_MSK, ++ FIELD_PREP(BMI323_FEAT_IO0_STP_CNT_MSK, val ? 1 : 0)); ++ ++ return 0; ++} ++ ++static int bmi323_read_steps(struct bmi323_data *data, int *val) ++{ ++ int ret; ++ ++ guard(mutex)(&data->mutex); ++ if (!FIELD_GET(BMI323_FEAT_IO0_STP_CNT_MSK, data->feature_events)) ++ return -EINVAL; ++ ++ ret = regmap_bulk_read(data->regmap, BMI323_FEAT_IO2_REG, ++ data->steps_count, ++ ARRAY_SIZE(data->steps_count)); ++ if (ret) ++ return ret; ++ ++ *val = get_unaligned_le32(data->steps_count); ++ ++ return IIO_VAL_INT; ++} ++ ++static int bmi323_read_axis(struct bmi323_data *data, ++ struct iio_chan_spec const *chan, int *val) ++{ ++ enum bmi323_sensor_type sensor; ++ unsigned int value; ++ u8 addr; ++ int ret; ++ ++ ret = bmi323_get_error_status(data); ++ if (ret) ++ return -EINVAL; ++ ++ sensor = bmi323_iio_to_sensor(chan->type); ++ addr = bmi323_hw[sensor].data + (chan->channel2 - IIO_MOD_X); ++ ++ scoped_guard(mutex, &data->mutex) { ++ ret = regmap_read(data->regmap, addr, &value); ++ if (ret) ++ return ret; ++ } ++ ++ *val = sign_extend32(value, chan->scan_type.realbits - 1); ++ ++ return IIO_VAL_INT; ++} ++ ++static int bmi323_get_temp_data(struct bmi323_data *data, int *val) ++{ ++ unsigned int value; ++ int ret; ++ ++ ret = bmi323_get_error_status(data); ++ if (ret) ++ return -EINVAL; ++ ++ scoped_guard(mutex, &data->mutex) { ++ ret = regmap_read(data->regmap, BMI323_TEMP_REG, &value); ++ if (ret) ++ return ret; ++ } ++ ++ *val = sign_extend32(value, 15); ++ ++ return IIO_VAL_INT; ++} ++ ++static int bmi323_get_odr(struct bmi323_data *data, ++ enum bmi323_sensor_type sensor, int *odr, int *uodr) ++{ ++ int ret, value, odr_raw; ++ ++ scoped_guard(mutex, &data->mutex) { ++ ret = regmap_read(data->regmap, bmi323_hw[sensor].config, &value); ++ if (ret) ++ return ret; ++ } ++ ++ odr_raw = FIELD_GET(BMI323_ACC_GYRO_CONF_ODR_MSK, value); ++ *odr = bmi323_acc_gyro_odr[odr_raw - 1][0]; ++ *uodr = bmi323_acc_gyro_odr[odr_raw - 1][1]; ++ ++ return IIO_VAL_INT_PLUS_MICRO; ++} ++ ++static int bmi323_configure_power_mode(struct bmi323_data *data, ++ enum bmi323_sensor_type sensor, ++ int odr_index) ++{ ++ enum bmi323_opr_mode mode; ++ ++ if (bmi323_acc_gyro_odr[odr_index][0] > 25) ++ mode = ACC_GYRO_MODE_CONTINOUS; ++ else ++ mode = ACC_GYRO_MODE_DUTYCYCLE; ++ ++ return bmi323_set_mode(data, sensor, mode); ++} ++ ++static int bmi323_set_odr(struct bmi323_data *data, ++ enum bmi323_sensor_type sensor, int odr, int uodr) ++{ ++ int odr_raw, ret; ++ ++ odr_raw = ARRAY_SIZE(bmi323_acc_gyro_odr); ++ ++ while (odr_raw--) ++ if (odr == bmi323_acc_gyro_odr[odr_raw][0] && ++ uodr == bmi323_acc_gyro_odr[odr_raw][1]) ++ break; ++ if (odr_raw < 0) ++ return -EINVAL; ++ ++ ret = bmi323_configure_power_mode(data, sensor, odr_raw); ++ if (ret) ++ return -EINVAL; ++ ++ guard(mutex)(&data->mutex); ++ data->odrhz[sensor] = bmi323_acc_gyro_odr[odr_raw][0]; ++ data->odrns[sensor] = bmi323_acc_gyro_odrns[odr_raw]; ++ ++ odr_raw++; ++ ++ return regmap_update_bits(data->regmap, bmi323_hw[sensor].config, ++ BMI323_ACC_GYRO_CONF_ODR_MSK, ++ FIELD_PREP(BMI323_ACC_GYRO_CONF_ODR_MSK, ++ odr_raw)); ++} ++ ++static int bmi323_get_scale(struct bmi323_data *data, ++ enum bmi323_sensor_type sensor, int *val2) ++{ ++ int ret, value, scale_raw; ++ ++ scoped_guard(mutex, &data->mutex) { ++ ret = regmap_read(data->regmap, bmi323_hw[sensor].config, ++ &value); ++ if (ret) ++ return ret; ++ } ++ ++ scale_raw = FIELD_GET(BMI323_ACC_GYRO_CONF_SCL_MSK, value); ++ *val2 = bmi323_hw[sensor].scale_table[scale_raw][1]; ++ ++ return IIO_VAL_INT_PLUS_MICRO; ++} ++ ++static int bmi323_set_scale(struct bmi323_data *data, ++ enum bmi323_sensor_type sensor, int val, int val2) ++{ ++ int scale_raw; ++ ++ scale_raw = bmi323_hw[sensor].scale_table_len; ++ ++ while (scale_raw--) ++ if (val == bmi323_hw[sensor].scale_table[scale_raw][0] && ++ val2 == bmi323_hw[sensor].scale_table[scale_raw][1]) ++ break; ++ if (scale_raw < 0) ++ return -EINVAL; ++ ++ guard(mutex)(&data->mutex); ++ return regmap_update_bits(data->regmap, bmi323_hw[sensor].config, ++ BMI323_ACC_GYRO_CONF_SCL_MSK, ++ FIELD_PREP(BMI323_ACC_GYRO_CONF_SCL_MSK, ++ scale_raw)); ++} ++ ++static int bmi323_read_avail(struct iio_dev *indio_dev, ++ struct iio_chan_spec const *chan, ++ const int **vals, int *type, int *length, ++ long mask) ++{ ++ enum bmi323_sensor_type sensor; ++ ++ switch (mask) { ++ case IIO_CHAN_INFO_SAMP_FREQ: ++ *type = IIO_VAL_INT_PLUS_MICRO; ++ *vals = (const int *)bmi323_acc_gyro_odr; ++ *length = ARRAY_SIZE(bmi323_acc_gyro_odr) * 2; ++ return IIO_AVAIL_LIST; ++ case IIO_CHAN_INFO_SCALE: ++ sensor = bmi323_iio_to_sensor(chan->type); ++ *type = IIO_VAL_INT_PLUS_MICRO; ++ *vals = (const int *)bmi323_hw[sensor].scale_table; ++ *length = bmi323_hw[sensor].scale_table_len * 2; ++ return IIO_AVAIL_LIST; ++ case IIO_CHAN_INFO_OVERSAMPLING_RATIO: ++ *type = IIO_VAL_INT; ++ *vals = (const int *)bmi323_accel_gyro_avrg; ++ *length = ARRAY_SIZE(bmi323_accel_gyro_avrg); ++ return IIO_AVAIL_LIST; ++ default: ++ return -EINVAL; ++ } ++} ++ ++static int bmi323_write_raw(struct iio_dev *indio_dev, ++ struct iio_chan_spec const *chan, int val, ++ int val2, long mask) ++{ ++ struct bmi323_data *data = iio_priv(indio_dev); ++ int ret; ++ ++ switch (mask) { ++ case IIO_CHAN_INFO_SAMP_FREQ: ++ ret = iio_device_claim_direct_mode(indio_dev); ++ if (ret) ++ return ret; ++ ++ ret = bmi323_set_odr(data, bmi323_iio_to_sensor(chan->type), ++ val, val2); ++ iio_device_release_direct_mode(indio_dev); ++ return ret; ++ case IIO_CHAN_INFO_SCALE: ++ ret = iio_device_claim_direct_mode(indio_dev); ++ if (ret) ++ return ret; ++ ++ ret = bmi323_set_scale(data, bmi323_iio_to_sensor(chan->type), ++ val, val2); ++ iio_device_release_direct_mode(indio_dev); ++ return ret; ++ case IIO_CHAN_INFO_OVERSAMPLING_RATIO: ++ ret = iio_device_claim_direct_mode(indio_dev); ++ if (ret) ++ return ret; ++ ++ ret = bmi323_set_average(data, bmi323_iio_to_sensor(chan->type), ++ val); ++ ++ iio_device_release_direct_mode(indio_dev); ++ return ret; ++ case IIO_CHAN_INFO_ENABLE: ++ return bmi323_enable_steps(data, val); ++ case IIO_CHAN_INFO_PROCESSED: ++ scoped_guard(mutex, &data->mutex) { ++ if (val || !FIELD_GET(BMI323_FEAT_IO0_STP_CNT_MSK, ++ data->feature_events)) ++ return -EINVAL; ++ ++ /* Clear step counter value */ ++ ret = bmi323_update_ext_reg(data, BMI323_STEP_SC1_REG, ++ BMI323_STEP_SC1_RST_CNT_MSK, ++ FIELD_PREP(BMI323_STEP_SC1_RST_CNT_MSK, ++ 1)); ++ } ++ return ret; ++ default: ++ return -EINVAL; ++ } ++} ++ ++static int bmi323_read_raw(struct iio_dev *indio_dev, ++ struct iio_chan_spec const *chan, int *val, ++ int *val2, long mask) ++{ ++ struct bmi323_data *data = iio_priv(indio_dev); ++ int ret; ++ ++ switch (mask) { ++ case IIO_CHAN_INFO_PROCESSED: ++ return bmi323_read_steps(data, val); ++ case IIO_CHAN_INFO_RAW: ++ switch (chan->type) { ++ case IIO_ACCEL: ++ case IIO_ANGL_VEL: ++ ret = iio_device_claim_direct_mode(indio_dev); ++ if (ret) ++ return ret; ++ ++ ret = bmi323_read_axis(data, chan, val); ++ ++ iio_device_release_direct_mode(indio_dev); ++ return ret; ++ case IIO_TEMP: ++ return bmi323_get_temp_data(data, val); ++ default: ++ return -EINVAL; ++ } ++ case IIO_CHAN_INFO_SAMP_FREQ: ++ return bmi323_get_odr(data, bmi323_iio_to_sensor(chan->type), ++ val, val2); ++ case IIO_CHAN_INFO_SCALE: ++ switch (chan->type) { ++ case IIO_ACCEL: ++ case IIO_ANGL_VEL: ++ *val = 0; ++ return bmi323_get_scale(data, ++ bmi323_iio_to_sensor(chan->type), ++ val2); ++ case IIO_TEMP: ++ *val = BMI323_TEMP_SCALE / MEGA; ++ *val2 = BMI323_TEMP_SCALE % MEGA; ++ return IIO_VAL_INT_PLUS_MICRO; ++ default: ++ return -EINVAL; ++ } ++ case IIO_CHAN_INFO_OVERSAMPLING_RATIO: ++ return bmi323_get_average(data, ++ bmi323_iio_to_sensor(chan->type), ++ val); ++ case IIO_CHAN_INFO_OFFSET: ++ switch (chan->type) { ++ case IIO_TEMP: ++ *val = BMI323_TEMP_OFFSET; ++ return IIO_VAL_INT; ++ default: ++ return -EINVAL; ++ } ++ case IIO_CHAN_INFO_ENABLE: ++ scoped_guard(mutex, &data->mutex) ++ *val = FIELD_GET(BMI323_FEAT_IO0_STP_CNT_MSK, ++ data->feature_events); ++ return IIO_VAL_INT; ++ default: ++ return -EINVAL; ++ } ++} ++ ++static const struct iio_info bmi323_info = { ++ .read_raw = bmi323_read_raw, ++ .write_raw = bmi323_write_raw, ++ .read_avail = bmi323_read_avail, ++ .hwfifo_set_watermark = bmi323_set_watermark, ++ .write_event_config = bmi323_write_event_config, ++ .read_event_config = bmi323_read_event_config, ++ .write_event_value = bmi323_write_event_value, ++ .read_event_value = bmi323_read_event_value, ++ .event_attrs = &bmi323_event_attribute_group, ++}; ++ ++#define BMI323_SCAN_MASK_ACCEL_3AXIS \ ++ (BIT(BMI323_ACCEL_X) | BIT(BMI323_ACCEL_Y) | BIT(BMI323_ACCEL_Z)) ++ ++#define BMI323_SCAN_MASK_GYRO_3AXIS \ ++ (BIT(BMI323_GYRO_X) | BIT(BMI323_GYRO_Y) | BIT(BMI323_GYRO_Z)) ++ ++static const unsigned long bmi323_avail_scan_masks[] = { ++ /* 3-axis accel */ ++ BMI323_SCAN_MASK_ACCEL_3AXIS, ++ /* 3-axis gyro */ ++ BMI323_SCAN_MASK_GYRO_3AXIS, ++ /* 3-axis accel + 3-axis gyro */ ++ BMI323_SCAN_MASK_ACCEL_3AXIS | BMI323_SCAN_MASK_GYRO_3AXIS, ++ 0 ++}; ++ ++static int bmi323_int_pin_config(struct bmi323_data *data, ++ enum bmi323_irq_pin irq_pin, ++ bool active_high, bool open_drain, bool latch) ++{ ++ unsigned int mask, field_value; ++ int ret; ++ ++ ret = regmap_update_bits(data->regmap, BMI323_IO_INT_CONF_REG, ++ BMI323_IO_INT_LTCH_MSK, ++ FIELD_PREP(BMI323_IO_INT_LTCH_MSK, latch)); ++ if (ret) ++ return ret; ++ ++ ret = bmi323_update_ext_reg(data, BMI323_GEN_SET1_REG, ++ BMI323_GEN_HOLD_DUR_MSK, ++ FIELD_PREP(BMI323_GEN_HOLD_DUR_MSK, 0)); ++ if (ret) ++ return ret; ++ ++ switch (irq_pin) { ++ case BMI323_IRQ_INT1: ++ mask = BMI323_IO_INT1_LVL_OD_OP_MSK; ++ ++ field_value = FIELD_PREP(BMI323_IO_INT1_LVL_MSK, active_high) | ++ FIELD_PREP(BMI323_IO_INT1_OD_MSK, open_drain) | ++ FIELD_PREP(BMI323_IO_INT1_OP_EN_MSK, 1); ++ break; ++ case BMI323_IRQ_INT2: ++ mask = BMI323_IO_INT2_LVL_OD_OP_MSK; ++ ++ field_value = FIELD_PREP(BMI323_IO_INT2_LVL_MSK, active_high) | ++ FIELD_PREP(BMI323_IO_INT2_OD_MSK, open_drain) | ++ FIELD_PREP(BMI323_IO_INT2_OP_EN_MSK, 1); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ return regmap_update_bits(data->regmap, BMI323_IO_INT_CTR_REG, mask, ++ field_value); ++} ++ ++static int bmi323_trigger_probe(struct bmi323_data *data, ++ struct iio_dev *indio_dev) ++{ ++ bool open_drain, active_high, latch; ++ struct fwnode_handle *fwnode; ++ enum bmi323_irq_pin irq_pin; ++ int ret, irq, irq_type; ++ struct irq_data *desc; ++ ++ fwnode = dev_fwnode(data->dev); ++ if (!fwnode) ++ return -ENODEV; ++ ++ irq = fwnode_irq_get_byname(fwnode, "INT1"); ++ if (irq > 0) { ++ irq_pin = BMI323_IRQ_INT1; ++ } else { ++ irq = fwnode_irq_get_byname(fwnode, "INT2"); ++ if (irq < 0) ++ return 0; ++ ++ irq_pin = BMI323_IRQ_INT2; ++ } ++ ++ desc = irq_get_irq_data(irq); ++ if (!desc) ++ return dev_err_probe(data->dev, -EINVAL, ++ "Could not find IRQ %d\n", irq); ++ ++ irq_type = irqd_get_trigger_type(desc); ++ switch (irq_type) { ++ case IRQF_TRIGGER_RISING: ++ latch = false; ++ active_high = true; ++ break; ++ case IRQF_TRIGGER_HIGH: ++ latch = true; ++ active_high = true; ++ break; ++ case IRQF_TRIGGER_FALLING: ++ latch = false; ++ active_high = false; ++ break; ++ case IRQF_TRIGGER_LOW: ++ latch = true; ++ active_high = false; ++ break; ++ default: ++ return dev_err_probe(data->dev, -EINVAL, ++ "Invalid interrupt type 0x%x specified\n", ++ irq_type); ++ } ++ ++ open_drain = fwnode_property_read_bool(fwnode, "drive-open-drain"); ++ ++ ret = bmi323_int_pin_config(data, irq_pin, active_high, open_drain, ++ latch); ++ if (ret) ++ return dev_err_probe(data->dev, ret, ++ "Failed to configure irq line\n"); ++ ++ data->trig = devm_iio_trigger_alloc(data->dev, "%s-trig-%d", ++ indio_dev->name, irq_pin); ++ if (!data->trig) ++ return -ENOMEM; ++ ++ data->trig->ops = &bmi323_trigger_ops; ++ iio_trigger_set_drvdata(data->trig, data); ++ ++ ret = devm_request_threaded_irq(data->dev, irq, NULL, ++ bmi323_irq_thread_handler, ++ IRQF_ONESHOT, "bmi323-int", indio_dev); ++ if (ret) ++ return dev_err_probe(data->dev, ret, "Failed to request IRQ\n"); ++ ++ ret = devm_iio_trigger_register(data->dev, data->trig); ++ if (ret) ++ return dev_err_probe(data->dev, ret, ++ "Trigger registration failed\n"); ++ ++ data->irq_pin = irq_pin; ++ ++ return 0; ++} ++ ++static int bmi323_feature_engine_enable(struct bmi323_data *data, bool en) ++{ ++ unsigned int feature_status; ++ int ret; ++ ++ if (!en) ++ return regmap_write(data->regmap, BMI323_FEAT_CTRL_REG, 0); ++ ++ ret = regmap_write(data->regmap, BMI323_FEAT_IO2_REG, 0x012c); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write(data->regmap, BMI323_FEAT_IO_STATUS_REG, ++ BMI323_FEAT_IO_STATUS_MSK); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write(data->regmap, BMI323_FEAT_CTRL_REG, ++ BMI323_FEAT_ENG_EN_MSK); ++ if (ret) ++ return ret; ++ ++ /* ++ * It takes around 4 msec to enable the Feature engine, so check ++ * the status of the feature engine every 2 msec for a maximum ++ * of 5 trials. ++ */ ++ ret = regmap_read_poll_timeout(data->regmap, BMI323_FEAT_IO1_REG, ++ feature_status, ++ FIELD_GET(BMI323_FEAT_IO1_ERR_MSK, ++ feature_status) == 1, ++ BMI323_FEAT_ENG_POLL, ++ BMI323_FEAT_ENG_TIMEOUT); ++ if (ret) ++ return dev_err_probe(data->dev, -EINVAL, ++ "Failed to enable feature engine\n"); ++ ++ return 0; ++} ++ ++static void bmi323_disable(void *data_ptr) ++{ ++ struct bmi323_data *data = data_ptr; ++ ++ bmi323_set_mode(data, BMI323_ACCEL, ACC_GYRO_MODE_DISABLE); ++ bmi323_set_mode(data, BMI323_GYRO, ACC_GYRO_MODE_DISABLE); ++} ++ ++static int bmi323_set_bw(struct bmi323_data *data, ++ enum bmi323_sensor_type sensor, enum bmi323_3db_bw bw) ++{ ++ return regmap_update_bits(data->regmap, bmi323_hw[sensor].config, ++ BMI323_ACC_GYRO_CONF_BW_MSK, ++ FIELD_PREP(BMI323_ACC_GYRO_CONF_BW_MSK, bw)); ++} ++ ++static int bmi323_init(struct bmi323_data *data) ++{ ++ int ret, val; ++ ++ /* ++ * Perform soft reset to make sure the device is in a known state after ++ * start up. A delay of 1.5 ms is required after reset. ++ * See datasheet section 5.17 "Soft Reset". ++ */ ++ ret = regmap_write(data->regmap, BMI323_CMD_REG, BMI323_RST_VAL); ++ if (ret) ++ return ret; ++ ++ usleep_range(1500, 2000); ++ ++ /* ++ * Dummy read is required to enable SPI interface after reset. ++ * See datasheet section 7.2.1 "Protocol Selection". ++ */ ++ regmap_read(data->regmap, BMI323_CHIP_ID_REG, &val); ++ ++ ret = regmap_read(data->regmap, BMI323_STATUS_REG, &val); ++ if (ret) ++ return ret; ++ ++ if (!FIELD_GET(BMI323_STATUS_POR_MSK, val)) ++ return dev_err_probe(data->dev, -EINVAL, ++ "Sensor initialization error\n"); ++ ++ ret = regmap_read(data->regmap, BMI323_CHIP_ID_REG, &val); ++ if (ret) ++ return ret; ++ ++ if (FIELD_GET(BMI323_CHIP_ID_MSK, val) != BMI323_CHIP_ID_VAL) ++ return dev_err_probe(data->dev, -EINVAL, "Chip ID mismatch\n"); ++ ++ ret = bmi323_feature_engine_enable(data, true); ++ if (ret) ++ return ret; ++ ++ ret = regmap_read(data->regmap, BMI323_ERR_REG, &val); ++ if (ret) ++ return ret; ++ ++ if (val) ++ return dev_err_probe(data->dev, -EINVAL, ++ "Sensor power error = 0x%x\n", val); ++ ++ /* ++ * Set the Bandwidth coefficient which defines the 3 dB cutoff ++ * frequency in relation to the ODR. ++ */ ++ ret = bmi323_set_bw(data, BMI323_ACCEL, BMI323_BW_ODR_BY_2); ++ if (ret) ++ return ret; ++ ++ ret = bmi323_set_bw(data, BMI323_GYRO, BMI323_BW_ODR_BY_2); ++ if (ret) ++ return ret; ++ ++ ret = bmi323_set_odr(data, BMI323_ACCEL, 25, 0); ++ if (ret) ++ return ret; ++ ++ ret = bmi323_set_odr(data, BMI323_GYRO, 25, 0); ++ if (ret) ++ return ret; ++ ++ return devm_add_action_or_reset(data->dev, bmi323_disable, data); ++} ++ ++int bmi323_core_probe(struct device *dev) ++{ ++ static const char * const regulator_names[] = { "vdd", "vddio" }; ++ struct iio_dev *indio_dev; ++ struct bmi323_data *data; ++ struct regmap *regmap; ++ int ret; ++ ++ regmap = dev_get_regmap(dev, NULL); ++ if (!regmap) ++ return dev_err_probe(dev, -ENODEV, "Failed to get regmap\n"); ++ ++ indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); ++ if (!indio_dev) ++ return dev_err_probe(dev, -ENOMEM, ++ "Failed to allocate device\n"); ++ ++ ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(regulator_names), ++ regulator_names); ++ if (ret) ++ return dev_err_probe(dev, ret, "Failed to enable regulators\n"); ++ ++ data = iio_priv(indio_dev); ++ data->dev = dev; ++ data->regmap = regmap; ++ mutex_init(&data->mutex); ++ ++ ret = bmi323_init(data); ++ if (ret) ++ return -EINVAL; ++ ++ ret = iio_read_mount_matrix(dev, &data->orientation); ++ if (ret) ++ return ret; ++ ++ indio_dev->name = "bmi323-imu"; ++ indio_dev->info = &bmi323_info; ++ indio_dev->channels = bmi323_channels; ++ indio_dev->num_channels = ARRAY_SIZE(bmi323_channels); ++ indio_dev->available_scan_masks = bmi323_avail_scan_masks; ++ indio_dev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE; ++ dev_set_drvdata(data->dev, indio_dev); ++ ++ ret = bmi323_trigger_probe(data, indio_dev); ++ if (ret) ++ return -EINVAL; ++ ++ ret = devm_iio_triggered_buffer_setup_ext(data->dev, indio_dev, ++ &iio_pollfunc_store_time, ++ bmi323_trigger_handler, ++ IIO_BUFFER_DIRECTION_IN, ++ &bmi323_buffer_ops, ++ bmi323_fifo_attributes); ++ if (ret) ++ return dev_err_probe(data->dev, ret, ++ "Failed to setup trigger buffer\n"); ++ ++ ret = devm_iio_device_register(data->dev, indio_dev); ++ if (ret) ++ return dev_err_probe(data->dev, ret, ++ "Unable to register iio device\n"); ++ ++ return 0; ++} ++EXPORT_SYMBOL_NS_GPL(bmi323_core_probe, IIO_BMI323); ++ ++MODULE_DESCRIPTION("Bosch BMI323 IMU driver"); ++MODULE_AUTHOR("Jagath Jog J <jagathjog1996@gmail.com>"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/iio/imu/bmi323/bmi323_i2c.c b/drivers/iio/imu/bmi323/bmi323_i2c.c +new file mode 100644 +index 000000000000..0008e186367d +--- /dev/null ++++ b/drivers/iio/imu/bmi323/bmi323_i2c.c +@@ -0,0 +1,121 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * I2C driver for Bosch BMI323 6-Axis IMU. ++ * ++ * Copyright (C) 2023, Jagath Jog J <jagathjog1996@gmail.com> ++ */ ++ ++#include <linux/i2c.h> ++#include <linux/mod_devicetable.h> ++#include <linux/module.h> ++#include <linux/regmap.h> ++ ++#include "bmi323.h" ++ ++struct bmi323_i2c_priv { ++ struct i2c_client *i2c; ++ u8 i2c_rx_buffer[BMI323_FIFO_LENGTH_IN_BYTES + BMI323_I2C_DUMMY]; ++}; ++ ++/* ++ * From BMI323 datasheet section 4: Notes on the Serial Interface Support. ++ * Each I2C register read operation requires to read two dummy bytes before ++ * the actual payload. ++ */ ++static int bmi323_regmap_i2c_read(void *context, const void *reg_buf, ++ size_t reg_size, void *val_buf, ++ size_t val_size) ++{ ++ struct bmi323_i2c_priv *priv = context; ++ struct i2c_msg msgs[2]; ++ int ret; ++ ++ msgs[0].addr = priv->i2c->addr; ++ msgs[0].flags = priv->i2c->flags; ++ msgs[0].len = reg_size; ++ msgs[0].buf = (u8 *)reg_buf; ++ ++ msgs[1].addr = priv->i2c->addr; ++ msgs[1].len = val_size + BMI323_I2C_DUMMY; ++ msgs[1].buf = priv->i2c_rx_buffer; ++ msgs[1].flags = priv->i2c->flags | I2C_M_RD; ++ ++ ret = i2c_transfer(priv->i2c->adapter, msgs, ARRAY_SIZE(msgs)); ++ if (ret < 0) ++ return -EIO; ++ ++ memcpy(val_buf, priv->i2c_rx_buffer + BMI323_I2C_DUMMY, val_size); ++ ++ return 0; ++} ++ ++static int bmi323_regmap_i2c_write(void *context, const void *data, ++ size_t count) ++{ ++ struct bmi323_i2c_priv *priv = context; ++ u8 reg; ++ ++ reg = *(u8 *)data; ++ return i2c_smbus_write_i2c_block_data(priv->i2c, reg, ++ count - sizeof(u8), ++ data + sizeof(u8)); ++} ++ ++static struct regmap_bus bmi323_regmap_bus = { ++ .read = bmi323_regmap_i2c_read, ++ .write = bmi323_regmap_i2c_write, ++}; ++ ++const struct regmap_config bmi323_i2c_regmap_config = { ++ .reg_bits = 8, ++ .val_bits = 16, ++ .max_register = BMI323_CFG_RES_REG, ++ .val_format_endian = REGMAP_ENDIAN_LITTLE, ++}; ++ ++static int bmi323_i2c_probe(struct i2c_client *i2c) ++{ ++ struct device *dev = &i2c->dev; ++ struct bmi323_i2c_priv *priv; ++ struct regmap *regmap; ++ ++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ priv->i2c = i2c; ++ regmap = devm_regmap_init(dev, &bmi323_regmap_bus, priv, ++ &bmi323_i2c_regmap_config); ++ if (IS_ERR(regmap)) ++ return dev_err_probe(dev, PTR_ERR(regmap), ++ "Failed to initialize I2C Regmap\n"); ++ ++ return bmi323_core_probe(dev); ++} ++ ++static const struct i2c_device_id bmi323_i2c_ids[] = { ++ { "bmi323" }, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, bmi323_i2c_ids); ++ ++static const struct of_device_id bmi323_of_i2c_match[] = { ++ { .compatible = "bosch,bmi323" }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, bmi323_of_i2c_match); ++ ++static struct i2c_driver bmi323_i2c_driver = { ++ .driver = { ++ .name = "bmi323", ++ .of_match_table = bmi323_of_i2c_match, ++ }, ++ .probe = bmi323_i2c_probe, ++ .id_table = bmi323_i2c_ids, ++}; ++module_i2c_driver(bmi323_i2c_driver); ++ ++MODULE_DESCRIPTION("Bosch BMI323 IMU driver"); ++MODULE_AUTHOR("Jagath Jog J <jagathjog1996@gmail.com>"); ++MODULE_LICENSE("GPL"); ++MODULE_IMPORT_NS(IIO_BMI323); +diff --git a/drivers/iio/imu/bmi323/bmi323_spi.c b/drivers/iio/imu/bmi323/bmi323_spi.c +new file mode 100644 +index 000000000000..6dc3352dd714 +--- /dev/null ++++ b/drivers/iio/imu/bmi323/bmi323_spi.c +@@ -0,0 +1,92 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * SPI driver for Bosch BMI323 6-Axis IMU. ++ * ++ * Copyright (C) 2023, Jagath Jog J <jagathjog1996@gmail.com> ++ */ ++ ++#include <linux/mod_devicetable.h> ++#include <linux/module.h> ++#include <linux/regmap.h> ++#include <linux/spi/spi.h> ++ ++#include "bmi323.h" ++ ++/* ++ * From BMI323 datasheet section 4: Notes on the Serial Interface Support. ++ * Each SPI register read operation requires to read one dummy byte before ++ * the actual payload. ++ */ ++static int bmi323_regmap_spi_read(void *context, const void *reg_buf, ++ size_t reg_size, void *val_buf, ++ size_t val_size) ++{ ++ struct spi_device *spi = context; ++ ++ return spi_write_then_read(spi, reg_buf, reg_size, val_buf, val_size); ++} ++ ++static int bmi323_regmap_spi_write(void *context, const void *data, ++ size_t count) ++{ ++ struct spi_device *spi = context; ++ u8 *data_buff = (u8 *)data; ++ ++ data_buff[1] = data_buff[0]; ++ return spi_write(spi, data_buff + 1, count - 1); ++} ++ ++static struct regmap_bus bmi323_regmap_bus = { ++ .read = bmi323_regmap_spi_read, ++ .write = bmi323_regmap_spi_write, ++}; ++ ++const struct regmap_config bmi323_spi_regmap_config = { ++ .reg_bits = 8, ++ .val_bits = 16, ++ .pad_bits = 8, ++ .read_flag_mask = BIT(7), ++ .max_register = BMI323_CFG_RES_REG, ++ .val_format_endian = REGMAP_ENDIAN_LITTLE, ++}; ++ ++static int bmi323_spi_probe(struct spi_device *spi) ++{ ++ struct device *dev = &spi->dev; ++ struct regmap *regmap; ++ ++ regmap = devm_regmap_init(dev, &bmi323_regmap_bus, dev, ++ &bmi323_spi_regmap_config); ++ if (IS_ERR(regmap)) ++ return dev_err_probe(dev, PTR_ERR(regmap), ++ "Failed to initialize SPI Regmap\n"); ++ ++ return bmi323_core_probe(dev); ++} ++ ++static const struct spi_device_id bmi323_spi_ids[] = { ++ { "bmi323" }, ++ { } ++}; ++MODULE_DEVICE_TABLE(spi, bmi323_spi_ids); ++ ++static const struct of_device_id bmi323_of_spi_match[] = { ++ { .compatible = "bosch,bmi323" }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, bmi323_of_spi_match); ++ ++static struct spi_driver bmi323_spi_driver = { ++ .driver = { ++ .name = "bmi323", ++ .of_match_table = bmi323_of_spi_match, ++ }, ++ .probe = bmi323_spi_probe, ++ .id_table = bmi323_spi_ids, ++}; ++module_spi_driver(bmi323_spi_driver); ++ ++MODULE_DESCRIPTION("Bosch BMI323 IMU driver"); ++MODULE_AUTHOR("Jagath Jog J <jagathjog1996@gmail.com>"); ++MODULE_LICENSE("GPL"); ++MODULE_IMPORT_NS(IIO_BMI323); diff --git a/0002-iio-imu-bmi323-Make-the-local-structures-static.patch b/0002-iio-imu-bmi323-Make-the-local-structures-static.patch new file mode 100644 index 000000000000..decd8c43e675 --- /dev/null +++ b/0002-iio-imu-bmi323-Make-the-local-structures-static.patch @@ -0,0 +1,37 @@ +Make the local structures static within their respective driver files. + +Reported-by: kernel test robot <lkp@intel.com> +Closes: https://lore.kernel.org/oe-kbuild-all/202311070530.qKhLTz1Y-lkp@intel.com/ +Fixes: b512c767e7bc ("iio: imu: Add driver for BMI323 IMU") +Signed-off-by: Jagath Jog J <jagathjog1996@gmail.com> +--- + drivers/iio/imu/bmi323/bmi323_i2c.c | 2 +- + drivers/iio/imu/bmi323/bmi323_spi.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/iio/imu/bmi323/bmi323_i2c.c b/drivers/iio/imu/bmi323/bmi323_i2c.c +index 0008e186367d..20a8001b9956 100644 +--- a/drivers/iio/imu/bmi323/bmi323_i2c.c ++++ b/drivers/iio/imu/bmi323/bmi323_i2c.c +@@ -66,7 +66,7 @@ static struct regmap_bus bmi323_regmap_bus = { + .write = bmi323_regmap_i2c_write, + }; + +-const struct regmap_config bmi323_i2c_regmap_config = { ++static const struct regmap_config bmi323_i2c_regmap_config = { + .reg_bits = 8, + .val_bits = 16, + .max_register = BMI323_CFG_RES_REG, +diff --git a/drivers/iio/imu/bmi323/bmi323_spi.c b/drivers/iio/imu/bmi323/bmi323_spi.c +index 6dc3352dd714..7b1e8127d0dd 100644 +--- a/drivers/iio/imu/bmi323/bmi323_spi.c ++++ b/drivers/iio/imu/bmi323/bmi323_spi.c +@@ -41,7 +41,7 @@ static struct regmap_bus bmi323_regmap_bus = { + .write = bmi323_regmap_spi_write, + }; + +-const struct regmap_config bmi323_spi_regmap_config = { ++static const struct regmap_config bmi323_spi_regmap_config = { + .reg_bits = 8, + .val_bits = 16, + .pad_bits = 8, diff --git a/0003-iio-imu_Add_ROG_ALLY_bmi323-support.patch b/0003-iio-imu_Add_ROG_ALLY_bmi323-support.patch new file mode 100644 index 000000000000..4111417f6ac9 --- /dev/null +++ b/0003-iio-imu_Add_ROG_ALLY_bmi323-support.patch @@ -0,0 +1,54 @@ +diff --git a/drivers/iio/accel/bmc150-accel-core.c b/drivers/iio/accel/bmc150-accel-core.c +index 1105918..d665a6e 100644 +--- a/drivers/iio/accel/bmc150-accel-core.c ++++ b/drivers/iio/accel/bmc150-accel-core.c +@@ -10,6 +10,7 @@ + #include <linux/delay.h> + #include <linux/slab.h> + #include <linux/acpi.h> ++#include <linux/dmi.h> + #include <linux/of_irq.h> + #include <linux/pm.h> + #include <linux/pm_runtime.h> +@@ -1670,6 +1671,8 @@ int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq, + struct iio_dev *indio_dev; + int ret; + ++ if (dmi_match(DMI_BOARD_NAME, "RC71L") || (dmi_match(DMI_BOARD_NAME, "AB05-AMD") && dmi_match(DMI_PRODUCT_NAME, "AIR Plus"))) ++ return -ENODEV; // Abort loading bmc150 for ASUS ROG ALLY, Ayaneo Air Plus + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; +diff --git a/drivers/iio/imu/bmi323/bmi323_i2c.c b/drivers/iio/imu/bmi323/bmi323_i2c.c +index 20a8001..346ba2d 100644 +--- a/drivers/iio/imu/bmi323/bmi323_i2c.c ++++ b/drivers/iio/imu/bmi323/bmi323_i2c.c +@@ -5,6 +5,7 @@ + * Copyright (C) 2023, Jagath Jog J <jagathjog1996@gmail.com> + */ + ++#include <linux/acpi.h> + #include <linux/i2c.h> + #include <linux/mod_devicetable.h> + #include <linux/module.h> +@@ -93,6 +94,12 @@ static int bmi323_i2c_probe(struct i2c_client *i2c) + return bmi323_core_probe(dev); + } + ++static const struct acpi_device_id bmi323_acpi_match[] = { ++ {"BOSC0200"}, ++ { }, ++}; ++MODULE_DEVICE_TABLE(acpi, bmi323_acpi_match); ++ + static const struct i2c_device_id bmi323_i2c_ids[] = { + { "bmi323" }, + { } +@@ -109,6 +116,7 @@ static struct i2c_driver bmi323_i2c_driver = { + .driver = { + .name = "bmi323", + .of_match_table = bmi323_of_i2c_match, ++ .acpi_match_table = ACPI_PTR(bmi323_acpi_match), + }, + .probe = bmi323_i2c_probe, + .id_table = bmi323_i2c_ids, diff --git a/0004-iio-imu-Load_ROG_ALLY_mount_matrix.patch b/0004-iio-imu-Load_ROG_ALLY_mount_matrix.patch new file mode 100644 index 000000000000..7e8153b867ef --- /dev/null +++ b/0004-iio-imu-Load_ROG_ALLY_mount_matrix.patch @@ -0,0 +1,51 @@ +diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c +index d752e9c..b495dba 100644 +--- a/drivers/iio/industrialio-core.c ++++ b/drivers/iio/industrialio-core.c +@@ -13,6 +13,7 @@ + #include <linux/cdev.h> + #include <linux/debugfs.h> + #include <linux/device.h> ++#include <linux/dmi.h> + #include <linux/err.h> + #include <linux/fs.h> + #include <linux/idr.h> +@@ -571,6 +572,14 @@ static const struct iio_mount_matrix iio_mount_idmatrix = { + } + }; + ++static const struct iio_mount_matrix iio_mount_flip_x_z_matrix = { ++ .rotation = { ++ "-1", "0", "0", ++ "0", "1", "0", ++ "0", "0", "-1" ++ } ++}; ++ + static int iio_setup_mount_idmatrix(const struct device *dev, + struct iio_mount_matrix *matrix) + { +@@ -579,6 +588,14 @@ static int iio_setup_mount_idmatrix(const struct device *dev, + return 0; + } + ++static int iio_setup_mount_flip_x_z_matrix(const struct device *dev, ++ struct iio_mount_matrix *matrix) ++{ ++ *matrix = iio_mount_flip_x_z_matrix; ++ dev_info(dev, "using flipped X-axis and flipped Z-axis mounting matrix...\n"); ++ return 0; ++} ++ + ssize_t iio_show_mount_matrix(struct iio_dev *indio_dev, uintptr_t priv, + const struct iio_chan_spec *chan, char *buf) + { +@@ -615,6 +632,8 @@ int iio_read_mount_matrix(struct device *dev, struct iio_mount_matrix *matrix) + int err; + + err = device_property_read_string_array(dev, "mount-matrix", matrix->rotation, len); ++ if (dmi_match(DMI_BOARD_NAME, "RC71L")) ++ return iio_setup_mount_flip_x_z_matrix(dev, matrix); + if (err == len) + return 0; + diff --git a/0005-iio-imu-ASUS-ROG-ALLY-force-INT1-IRQ.patch b/0005-iio-imu-ASUS-ROG-ALLY-force-INT1-IRQ.patch new file mode 100644 index 000000000000..292c7bebb453 --- /dev/null +++ b/0005-iio-imu-ASUS-ROG-ALLY-force-INT1-IRQ.patch @@ -0,0 +1,40 @@ +diff --git a/drivers/iio/imu/bmi323/bmi323_core.c b/drivers/iio/imu/bmi323/bmi323_core.c +index 0bd5ded..eae7756 100644 +--- a/drivers/iio/imu/bmi323/bmi323_core.c ++++ b/drivers/iio/imu/bmi323/bmi323_core.c +@@ -10,6 +10,7 @@ + #include <linux/bitfield.h> + #include <linux/cleanup.h> + #include <linux/device.h> ++#include <linux/dmi.h> + #include <linux/interrupt.h> + #include <linux/minmax.h> + #include <linux/module.h> +@@ -1870,6 +1871,8 @@ static int bmi323_trigger_probe(struct bmi323_data *data, + return -ENODEV; + + irq = fwnode_irq_get_byname(fwnode, "INT1"); ++ if (dmi_match(DMI_BOARD_NAME, "RC71L")) ++ irq = 1; // force IRQ INT1 for ASUS ROG ALLY + if (irq > 0) { + irq_pin = BMI323_IRQ_INT1; + } else { +@@ -1886,6 +1889,8 @@ static int bmi323_trigger_probe(struct bmi323_data *data, + "Could not find IRQ %d\n", irq); + + irq_type = irqd_get_trigger_type(desc); ++ if (dmi_match(DMI_BOARD_NAME, "RC71L")) ++ irq_type = IRQF_TRIGGER_RISING; // forcing trigger type for ASUS ROG ALLY + switch (irq_type) { + case IRQF_TRIGGER_RISING: + latch = false; +@@ -1910,7 +1915,8 @@ static int bmi323_trigger_probe(struct bmi323_data *data, + } + + open_drain = fwnode_property_read_bool(fwnode, "drive-open-drain"); +- ++ if (dmi_match(DMI_BOARD_NAME, "RC71L")) ++ open_drain = false; // forcing whether open drain (true) or push-pull (false) for ROG ALLY + ret = bmi323_int_pin_config(data, irq_pin, active_high, open_drain, + latch); + if (ret) diff --git a/0999-patch_realtek.patch b/0999-patch_realtek.patch index 2513ec48db10..81f7ee33f9bf 100644 --- a/0999-patch_realtek.patch +++ b/0999-patch_realtek.patch @@ -5,6 +5,6 @@ SND_PCI_QUIRK(0x103c, 0x87f6, "HP Spectre x360 14", ALC245_FIXUP_HP_X360_AMP), SND_PCI_QUIRK(0x103c, 0x87f7, "HP Spectre x360 14", ALC245_FIXUP_HP_X360_AMP), + SND_PCI_QUIRK(0x103c, 0x89da, "HP Spectre x360 14", ALC245_FIXUP_HP_X360_AMP), + SND_PCI_QUIRK(0x103c, 0x87fe, "HP Laptop 15s-fq2xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2), SND_PCI_QUIRK(0x103c, 0x8805, "HP ProBook 650 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x880d, "HP EliteBook 830 G8 Notebook PC", ALC285_FIXUP_HP_GPIO_LED), - SND_PCI_QUIRK(0x103c, 0x8811, "HP Spectre x360 15-eb1xxx", ALC285_FIXUP_HP_SPECTRE_X360_EB1), @@ -12,7 +12,7 @@ pkgbase=linux-jcore pkgname=('linux-jcore' 'linux-jcore-headers') _kernelname=-jcore _hostname=jcore -pkgver=6.6.6 +pkgver=6.6.25 pkgrel=2 pkgdesc="Kernel for Manjaro/EndeavourOS/Arch (ACS override patch include)" arch=('x86_64') @@ -22,7 +22,7 @@ makedepends=(bc docbook-xsl libelf pahole python-sphinx git inetutils kmod xmlto replaces=('linux-acs-manjaro' 'linux-acs-manjaro-headers') options=('!strip') -source=("https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-$pkgver.tar.xz" +source=(https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-$pkgver.tar.xz config # Upstream Patches # ARCH Patches @@ -32,13 +32,10 @@ source=("https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-$pkgver.tar.xz" # Realtek patch 0999-patch_realtek.patch # ROG ALLY Patches - 0000-hid-asus-add-const-to-read-only-outgoing-usb-buffer.patch - 0001-hid-asus-reset-the-backlight-brightness-level-on-resume.patch - v14.1-0001-HID-asus-fix-more-n-key-report-descriptors-if-.patch - v14.1-0002-HID-asus-make-asus_kbd_init-generic-remove-rog.patch - v14.1-0003-HID-asus-add-ROG-Ally-N-Key-ID-and-keycodes.patch - v14.1-0004-HID-asus-add-ROG-Ally-xpad-settings.patch - v14.1-fix-defaults1.patch + v14.7-0001-HID-asus-fix-more-n-key-report-descriptors-if-.patch + v14.7-0002-HID-asus-make-asus_kbd_init-generic-remove-rog.patch + v14.7-0003-HID-asus-add-ROG-Ally-N-Key-ID-and-keycodes.patch + v14.7-0004-HID-asus-add-ROG-Ally-xpad-settings.patch 0006-platform-x86-asus-wmi-disable-USB0-hub-on-ROG-Ally-b.patch 0007-mt7921e_Perform_FLR_to_recovery_the_device.patch # AMD GPU reset patches @@ -50,24 +47,27 @@ source=("https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-$pkgver.tar.xz" 0001-ALSA-hda-cs35l41-Improve-support-for-ASUS-ROG-Ally.patch # Additional ALLY patches ROG-ALLY-NCT6775-PLATFORM.patch - 0001-ROG-ALLY-bmi323-device.patch + 0001-iio-imu_Add_driver_for_BMI323_IMU.patch + 0002-iio-imu-bmi323-Make-the-local-structures-static.patch + 0003-iio-imu_Add_ROG_ALLY_bmi323-support.patch + 0004-iio-imu-Load_ROG_ALLY_mount_matrix.patch + 0005-iio-imu-ASUS-ROG-ALLY-force-INT1-IRQ.patch # Steamdeck HID patches 0001-HID.patch + # OrangePi Neo patches + 0001-OrangePi-Neo-panel-orientation-quirk.patch # ACS override patch - '0999-acs.gitpatch') + 0999-acs.gitpatch) -sha256sums=('ebf70a917934b13169e1be5b95c3b6c2fea5bc14e6dc144f1efb8a0016b224c8' - '043ada1688a42e652bb0b339d2f9732c323c22da96bb2ca2bcf144a731c5e981' +sha256sums=('99d210be87908233a55b0fadc0dccd3b95926c0651b6b82e37350b2029de1f44' + '9736c7856f4dd543d2172e1cb8a63cabdd6ed6fbf314dfdb5fe4c60b74954a68' '05f04019d4a2ee072238c32860fa80d673687d84d78ef436ae9332b6fb788467' 'e1d17690dd21e8d5482b63ca66bfe6b478d39e8e8b59eedd53adb0a55ebc308d' - '3aa9f1ca47bb078f3c9a52fe61897cf4fe989068cd7e66bfa6644fd605fa40d2' - 'fb2cd8a3ea9d47bd78c99b8ece1f3959c20b4de97a7959a12650f989f5c724da' - '7f3194f1a7c5ebc27bbfa4559cfd9a2ccffddbbd2d259c0d9c68631cb66c5855' - '176adde8fc3069bd28393bf0c9d788f1b0f9a186678aec4dc17b0b081c57f97b' - '493fa177cf602f087e981e95fad3764e305f4c486d4c2ef78255388b913be9cf' - '50ea381758fb8a8566f38a509fe7cf0448c77eaec5103066cafc2ecf02db1e9f' - '970687b811034e722befde62bcf6d51c7442a217074ed0fb71460bb1803f4c64' - 'c00b23162fdbf50de375d8e444b6d59e2e3630cfac55ec1d06114b9dad00e542' + 'a99b684fe5bc7fdacc6f5b1f2b6593672fc5d1e676c4de03ec29723747fc574b' + 'b099ae83a3b561b8bff8b32b44b6f4835b99eb150c2314177aa0bc8ca96e2ead' + '10b60663195a65ec3b0f50b49e4c0af952369ee5afe95e11a69ffccefc020eb2' + '3c8b877dfaf85acf45b54c85a44fa269aa1512ea3781fe551cf6d4e2d69c992d' + '73aa4be8c1abcf1b24c9a5c5072e68da3da82df807f3ff49660a100d7634da1d' '836e88044263f7bc474ca466b3d0d98c39e265db94925c300d0b138492946a13' 'd673d034fbcd80426fd8d9c6af56537c5fe5b55fe49d74e313474d7fc285ecc1' '1f62542a889a6c2eafd43acd0699f54720ed891eeda66a4a9261d75b92f28b7f' @@ -76,8 +76,13 @@ sha256sums=('ebf70a917934b13169e1be5b95c3b6c2fea5bc14e6dc144f1efb8a0016b224c8' '79970a4729572cb25fd4644d66f38ecd5b3e1610a42ea4bbe436b501f3469fa2' '430a7f971d78d0873708e0ad38fba602ceafefd4da8ebbf9d9c591bc4799acb5' 'cfcd5c177423df8b7b98b0500fe7ab0757f895ed945c33e205963f0069c7a3be' - '5574a68b1c7733769835bb856a8c32e54398dfde59f264708672b87b73b3c6ea' + '708a9899f80db35fb0f06e0144c361eac9a9b2d154cf2fa388a0b4810847e24c' + '514fd03c17245ed0aaee63e8830c9b02b00efa0307f7e0989065edec6ae185f0' + 'fccdf24b25620dd8271bb3b52ddc53f8882dec26518258dc47e1469fed33e516' + 'c3b901db58288b5cc5d8a947ac8ffec339870b00aba493d68a39f65c4ff3d869' + '5792a59a0c726a205ae1c1728700ea3e6385231cadc2cfdd2db08295b100638c' '7c948773d758418d8a436067265d678c444827562c46b9fced2ff31ced108481' + 'aa2ff6edca0177b864868fdc2752d3a0eaaf5b801bd17e5c59dfd78999226d83' '458d7e024d33d4965b14b9b987f01a2884ff28761cff5da7c6a54132a95e9f36') prepare() { @@ -1,24 +1,25 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/x86 6.6.5-1 Kernel Configuration +# Linux/x86 6.6.24-1 Kernel Configuration # CONFIG_CC_VERSION_TEXT="gcc (GCC) 13.2.1 20230801" CONFIG_CC_IS_GCC=y CONFIG_GCC_VERSION=130201 CONFIG_CLANG_VERSION=0 CONFIG_AS_IS_GNU=y -CONFIG_AS_VERSION=24100 +CONFIG_AS_VERSION=24200 CONFIG_LD_IS_BFD=y -CONFIG_LD_VERSION=24100 +CONFIG_LD_VERSION=24200 CONFIG_LLD_VERSION=0 CONFIG_CC_CAN_LINK=y CONFIG_CC_CAN_LINK_STATIC=y CONFIG_CC_HAS_ASM_GOTO_OUTPUT=y CONFIG_CC_HAS_ASM_GOTO_TIED_OUTPUT=y +CONFIG_GCC_ASM_GOTO_OUTPUT_WORKAROUND=y CONFIG_TOOLS_SUPPORT_RELR=y CONFIG_CC_HAS_ASM_INLINE=y CONFIG_CC_HAS_NO_PROFILE_FN_ATTR=y -CONFIG_PAHOLE_VERSION=125 +CONFIG_PAHOLE_VERSION=126 CONFIG_IRQ_WORK=y CONFIG_BUILDTIME_TABLE_SORT=y CONFIG_THREAD_INFO_IN_TASK=y @@ -205,7 +206,7 @@ CONFIG_ARCH_SUPPORTS_NUMA_BALANCING=y CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH=y CONFIG_CC_HAS_INT128=y CONFIG_CC_IMPLICIT_FALLTHROUGH="-Wimplicit-fallthrough=5" -CONFIG_GCC11_NO_ARRAY_BOUNDS=y +CONFIG_GCC10_NO_ARRAY_BOUNDS=y CONFIG_CC_NO_ARRAY_BOUNDS=y CONFIG_ARCH_SUPPORTS_INT128=y CONFIG_NUMA_BALANCING=y @@ -469,7 +470,6 @@ CONFIG_X86_DIRECT_GBPAGES=y CONFIG_X86_CPA_STATISTICS=y CONFIG_X86_MEM_ENCRYPT=y CONFIG_AMD_MEM_ENCRYPT=y -# CONFIG_AMD_MEM_ENCRYPT_ACTIVE_BY_DEFAULT is not set CONFIG_NUMA=y CONFIG_AMD_NUMA=y CONFIG_X86_64_ACPI_NUMA=y @@ -563,6 +563,7 @@ CONFIG_CPU_IBRS_ENTRY=y CONFIG_CPU_SRSO=y CONFIG_SLS=y # CONFIG_GDS_FORCE_MITIGATION is not set +CONFIG_MITIGATION_RFDS=y CONFIG_ARCH_HAS_ADD_PAGES=y # @@ -1985,7 +1986,6 @@ CONFIG_BT_BNEP_MC_FILTER=y CONFIG_BT_BNEP_PROTO_FILTER=y CONFIG_BT_CMTP=m CONFIG_BT_HIDP=m -# CONFIG_BT_HS is not set CONFIG_BT_LE=y CONFIG_BT_LE_L2CAP_ECRED=y CONFIG_BT_6LOWPAN=m @@ -3504,7 +3504,6 @@ CONFIG_STMMAC_ETH=m CONFIG_STMMAC_PLATFORM=m CONFIG_DWMAC_GENERIC=m CONFIG_DWMAC_INTEL=m -CONFIG_DWMAC_LOONGSON=m CONFIG_STMMAC_PCI=m CONFIG_NET_VENDOR_SUN=y CONFIG_HAPPYMEAL=m @@ -4374,7 +4373,6 @@ CONFIG_TOUCHSCREEN_PENMOUNT=m CONFIG_TOUCHSCREEN_EDT_FT5X06=m CONFIG_TOUCHSCREEN_TOUCHRIGHT=m CONFIG_TOUCHSCREEN_TOUCHWIN=m -CONFIG_TOUCHSCREEN_TI_AM335X_TSC=m CONFIG_TOUCHSCREEN_PIXCIR=m CONFIG_TOUCHSCREEN_WDT87XX_I2C=m CONFIG_TOUCHSCREEN_WM831X=m @@ -5684,7 +5682,6 @@ CONFIG_MFD_SM501=m CONFIG_MFD_SM501_GPIO=y CONFIG_MFD_SKY81452=m CONFIG_MFD_SYSCON=y -CONFIG_MFD_TI_AM335X_TSCADC=m CONFIG_MFD_LP3943=m CONFIG_MFD_LP8788=y CONFIG_MFD_TI_LMU=m @@ -9558,7 +9555,6 @@ CONFIG_TI_ADS8344=m CONFIG_TI_ADS8688=m CONFIG_TI_ADS124S08=m CONFIG_TI_ADS131E08=m -CONFIG_TI_AM335X_ADC=m CONFIG_TI_LMP92064=m CONFIG_TI_TLC4541=m CONFIG_TI_TSC2046=m @@ -9800,6 +9796,9 @@ CONFIG_BMI160_SPI=m CONFIG_BOSCH_BNO055=m CONFIG_BOSCH_BNO055_SERIAL=m CONFIG_BOSCH_BNO055_I2C=m +CONFIG_BMI323=m +CONFIG_BMI323_I2C=m +CONFIG_BMI323_SPI=m CONFIG_FXOS8700=m CONFIG_FXOS8700_I2C=m CONFIG_FXOS8700_SPI=m @@ -11424,8 +11423,6 @@ CONFIG_DEBUG_LIST=y # CONFIG_DEBUG_MAPLE_TREE is not set # end of Debug kernel data structures -# CONFIG_DEBUG_CREDENTIALS is not set - # # RCU Debugging # diff --git a/v14.1-fix-defaults1.patch b/v14.1-fix-defaults1.patch deleted file mode 100644 index a057f043c432..000000000000 --- a/v14.1-fix-defaults1.patch +++ /dev/null @@ -1,63 +0,0 @@ -diff --git a/drivers/hid/hid-asus-rog.c b/drivers/hid/hid-asus-rog.c -index 91f3a7786893..d765ca7fc3a9 100644 ---- a/drivers/hid/hid-asus-rog.c -+++ b/drivers/hid/hid-asus-rog.c -@@ -1396,31 +1396,33 @@ static int asus_rog_ally_probe(struct hid_device *hdev, const struct rog_ops *op - } - // TODO: move these to functions - drvdata->rog_ally_data->mode = xpad_mode_game; -- drvdata->rog_ally_data->deadzones[xpad_mode_game][0][1] = 64; -- drvdata->rog_ally_data->deadzones[xpad_mode_game][0][3] = 64; -- drvdata->rog_ally_data->deadzones[xpad_mode_game][1][1] = 64; -- drvdata->rog_ally_data->deadzones[xpad_mode_game][1][3] = 64; -- -- drvdata->rog_ally_data->anti_deadzones[xpad_mode_game][0] = 64; -- drvdata->rog_ally_data->anti_deadzones[xpad_mode_game][1] = 64; -- -- drvdata->rog_ally_data->response_curve[xpad_mode_game][0][0] = 0x14; -- drvdata->rog_ally_data->response_curve[xpad_mode_game][0][1] = 0x14; -- drvdata->rog_ally_data->response_curve[xpad_mode_game][0][2] = 0x28; -- drvdata->rog_ally_data->response_curve[xpad_mode_game][0][3] = 0x28; -- drvdata->rog_ally_data->response_curve[xpad_mode_game][0][4] = 0x3c; -- drvdata->rog_ally_data->response_curve[xpad_mode_game][0][5] = 0x3c; -- drvdata->rog_ally_data->response_curve[xpad_mode_game][0][6] = 0x50; -- drvdata->rog_ally_data->response_curve[xpad_mode_game][0][7] = 0x50; -- -- drvdata->rog_ally_data->response_curve[xpad_mode_game][1][0] = 0x14; -- drvdata->rog_ally_data->response_curve[xpad_mode_game][1][1] = 0x14; -- drvdata->rog_ally_data->response_curve[xpad_mode_game][1][2] = 0x28; -- drvdata->rog_ally_data->response_curve[xpad_mode_game][1][3] = 0x28; -- drvdata->rog_ally_data->response_curve[xpad_mode_game][1][4] = 0x3c; -- drvdata->rog_ally_data->response_curve[xpad_mode_game][1][5] = 0x3c; -- drvdata->rog_ally_data->response_curve[xpad_mode_game][1][6] = 0x50; -- drvdata->rog_ally_data->response_curve[xpad_mode_game][1][7] = 0x50; -+ for (int i = 0; i < xpad_mode_mouse; i++) { -+ drvdata->rog_ally_data->deadzones[i][0][1] = 64; -+ drvdata->rog_ally_data->deadzones[i][0][3] = 64; -+ drvdata->rog_ally_data->deadzones[i][1][1] = 64; -+ drvdata->rog_ally_data->deadzones[i][1][3] = 64; -+ -+ drvdata->rog_ally_data->response_curve[i][0][0] = 0x14; -+ drvdata->rog_ally_data->response_curve[i][0][1] = 0x14; -+ drvdata->rog_ally_data->response_curve[i][0][2] = 0x28; -+ drvdata->rog_ally_data->response_curve[i][0][3] = 0x28; -+ drvdata->rog_ally_data->response_curve[i][0][4] = 0x3c; -+ drvdata->rog_ally_data->response_curve[i][0][5] = 0x3c; -+ drvdata->rog_ally_data->response_curve[i][0][6] = 0x50; -+ drvdata->rog_ally_data->response_curve[i][0][7] = 0x50; -+ -+ drvdata->rog_ally_data->response_curve[i][1][0] = 0x14; -+ drvdata->rog_ally_data->response_curve[i][1][1] = 0x14; -+ drvdata->rog_ally_data->response_curve[i][1][2] = 0x28; -+ drvdata->rog_ally_data->response_curve[i][1][3] = 0x28; -+ drvdata->rog_ally_data->response_curve[i][1][4] = 0x3c; -+ drvdata->rog_ally_data->response_curve[i][1][5] = 0x3c; -+ drvdata->rog_ally_data->response_curve[i][1][6] = 0x50; -+ drvdata->rog_ally_data->response_curve[i][1][7] = 0x50; -+ -+ drvdata->rog_ally_data->vibration_intensity[i][0] = 64; -+ drvdata->rog_ally_data->vibration_intensity[i][1] = 64; -+ } - - ret = __gamepad_set_mode(&hdev->dev, xpad_mode_game); - if (ret < 0) diff --git a/v14.1-0001-HID-asus-fix-more-n-key-report-descriptors-if-.patch b/v14.7-0001-HID-asus-fix-more-n-key-report-descriptors-if-.patch index b5fb39f5f4ae..3aa05b55031f 100644 --- a/v14.1-0001-HID-asus-fix-more-n-key-report-descriptors-if-.patch +++ b/v14.7-0001-HID-asus-fix-more-n-key-report-descriptors-if-.patch @@ -1,7 +1,7 @@ -From f311b6a3ff32c8221a0003c4a154aecbf04fb12c Mon Sep 17 00:00:00 2001 +From 5efbf21a6dc030b27e32cd632cfde1c3c7801075 Mon Sep 17 00:00:00 2001 From: "Luke D. Jones" <luke@ljones.dev> Date: Sat, 2 Dec 2023 17:27:23 +1300 -Subject: [PATCH v14.1 1/4] HID: asus: fix more n-key report descriptors if +Subject: [PATCH v14.7 1/4] HID: asus: fix more n-key report descriptors if n-key quirked Adjusts the report descriptor for N-Key devices to @@ -85,5 +85,5 @@ index 78cdfb8b9a7a..855972a4470f 100644 } -- -2.41.0 +2.43.0 diff --git a/v14.1-0002-HID-asus-make-asus_kbd_init-generic-remove-rog.patch b/v14.7-0002-HID-asus-make-asus_kbd_init-generic-remove-rog.patch index 2a2fa5ba18ce..f0f49674ceb1 100644 --- a/v14.1-0002-HID-asus-make-asus_kbd_init-generic-remove-rog.patch +++ b/v14.7-0002-HID-asus-make-asus_kbd_init-generic-remove-rog.patch @@ -1,7 +1,7 @@ -From 119615a0034ee5f8d7a949c1c9d992b1be125fcb Mon Sep 17 00:00:00 2001 +From d6b33439281d1b8cf93b0c5c5ecabcd9c6e7baad Mon Sep 17 00:00:00 2001 From: "Luke D. Jones" <luke@ljones.dev> Date: Sat, 2 Dec 2023 17:47:59 +1300 -Subject: [PATCH v14.1 2/4] HID: asus: make asus_kbd_init() generic, remove +Subject: [PATCH v14.7 2/4] HID: asus: make asus_kbd_init() generic, remove rog_nkey_led_init() Some of the n-key stuff is old and outdated, so @@ -126,5 +126,5 @@ index 855972a4470f..cdd998a761fe 100644 return ret; -- -2.41.0 +2.43.0 diff --git a/v14.1-0003-HID-asus-add-ROG-Ally-N-Key-ID-and-keycodes.patch b/v14.7-0003-HID-asus-add-ROG-Ally-N-Key-ID-and-keycodes.patch index a40a650b018d..a2a2785f1268 100644 --- a/v14.1-0003-HID-asus-add-ROG-Ally-N-Key-ID-and-keycodes.patch +++ b/v14.7-0003-HID-asus-add-ROG-Ally-N-Key-ID-and-keycodes.patch @@ -1,7 +1,7 @@ -From 2b1a33a519668105eb7261c2d8964da576be6146 Mon Sep 17 00:00:00 2001 +From 646c1ffacd59555825734bbcd2fa6e38100570c5 Mon Sep 17 00:00:00 2001 From: "Luke D. Jones" <luke@ljones.dev> Date: Wed, 29 Nov 2023 22:18:11 +1300 -Subject: [PATCH v14.1 3/4] HID: asus: add ROG Ally N-Key ID and keycodes +Subject: [PATCH v14.7 3/4] HID: asus: add ROG Ally N-Key ID and keycodes --- drivers/hid/hid-asus.c | 7 +++++++ @@ -34,7 +34,7 @@ index cdd998a761fe..3a1a6024d299 100644 USB_DEVICE_ID_ASUSTEK_ROG_CLAYMORE_II_KEYBOARD), QUIRK_ROG_CLAYMORE_II_KEYBOARD }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h -index c6e4e0d1f214..6debff9ad678 100644 +index 72046039d1be..ec9a41050446 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -208,6 +208,7 @@ @@ -46,5 +46,5 @@ index c6e4e0d1f214..6debff9ad678 100644 #define USB_DEVICE_ID_ASUSTEK_FX503VD_KEYBOARD 0x1869 -- -2.41.0 +2.43.0 diff --git a/v14.1-0004-HID-asus-add-ROG-Ally-xpad-settings.patch b/v14.7-0004-HID-asus-add-ROG-Ally-xpad-settings.patch index 13bfbd78c677..0d4d43d19751 100644 --- a/v14.1-0004-HID-asus-add-ROG-Ally-xpad-settings.patch +++ b/v14.7-0004-HID-asus-add-ROG-Ally-xpad-settings.patch @@ -1,7 +1,7 @@ -From fc88194fbc824967cce666a6e2ab4b47722f8d01 Mon Sep 17 00:00:00 2001 +From 9fd3de7abd22d7e67a8757e3f67410302359fec7 Mon Sep 17 00:00:00 2001 From: "Luke D. Jones" <luke@ljones.dev> Date: Fri, 1 Dec 2023 16:57:19 +1300 -Subject: [PATCH v14.1 4/4] HID: asus: add ROG Ally xpad settings +Subject: [PATCH v14.7 4/4] HID: asus: add ROG Ally xpad settings - move ROG specific stuff to new .c - add a header for common parts @@ -18,10 +18,10 @@ Subject: [PATCH v14.1 4/4] HID: asus: add ROG Ally xpad settings .../ABI/testing/sysfs-driver-hid-asus | 85 + drivers/hid/Makefile | 2 + drivers/hid/{hid-asus.c => hid-asus-core.c} | 71 +- - drivers/hid/hid-asus-rog.c | 1457 +++++++++++++++++ + drivers/hid/hid-asus-rog.c | 1469 +++++++++++++++++ drivers/hid/hid-asus-rog.h | 482 ++++++ drivers/hid/hid-asus.h | 58 + - 6 files changed, 2114 insertions(+), 41 deletions(-) + 6 files changed, 2126 insertions(+), 41 deletions(-) create mode 100644 Documentation/ABI/testing/sysfs-driver-hid-asus rename drivers/hid/{hid-asus.c => hid-asus-core.c} (96%) create mode 100644 drivers/hid/hid-asus-rog.c @@ -30,7 +30,7 @@ Subject: [PATCH v14.1 4/4] HID: asus: add ROG Ally xpad settings diff --git a/Documentation/ABI/testing/sysfs-driver-hid-asus b/Documentation/ABI/testing/sysfs-driver-hid-asus new file mode 100644 -index 000000000000..736233ebb38f +index 000000000000..df5b0c5b0702 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-driver-hid-asus @@ -0,0 +1,85 @@ @@ -73,6 +73,12 @@ index 000000000000..736233ebb38f +Contact: linux-input@vger.kernel.org +Description: Descriptive labels for joystick deadzone array. + ++What: /sys/bus/usb/devices/1-3:1.0/0003:0B05:1ABE.0001/axis_<x/y>_<left/right>/anti-deadzone ++Date: December 2023 ++Contact: linux-input@vger.kernel.org ++Description: Set the joystick anti-deadzone feature: ++ - range 0-32 (corresponds to 0-50%) ++ +What: /sys/bus/usb/devices/1-3:1.0/0003:0B05:1ABE.0001/axis_<x/y/z>_<left/right>/calibration +Date: December 2023 +Contact: linux-input@vger.kernel.org @@ -84,12 +90,6 @@ index 000000000000..736233ebb38f +Contact: linux-input@vger.kernel.org +Description: Descriptive labels for joystick and triggers calibration array. + -+What: /sys/bus/usb/devices/1-3:1.0/0003:0B05:1ABE.0001/axis_<x/y>_<left/right>/anti-deadzone -+Date: December 2023 -+Contact: linux-input@vger.kernel.org -+Description: Set the joystick anti-deadzone feature: -+ - range 0-64 (corresponds to 0-100%) -+ +What: /sys/bus/usb/devices/1-3:1.0/0003:0B05:1ABE.0001/axis_<x/y>_<left/right>/rc_point<n> +Date: December 2023 +Contact: linux-input@vger.kernel.org @@ -297,10 +297,10 @@ index 3a1a6024d299..026705c43ee1 100644 QUIRK_ROG_CLAYMORE_II_KEYBOARD }, diff --git a/drivers/hid/hid-asus-rog.c b/drivers/hid/hid-asus-rog.c new file mode 100644 -index 000000000000..f0a2b366a298 +index 000000000000..94b7c986576c --- /dev/null +++ b/drivers/hid/hid-asus-rog.c -@@ -0,0 +1,1457 @@ +@@ -0,0 +1,1469 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * HID driver for Asus ROG laptops and Ally @@ -481,7 +481,7 @@ index 000000000000..f0a2b366a298 + STR_TO_CODE_ELIF(2, 0x32, KB_B) + STR_TO_CODE_ELIF(2, 0x31, KB_N) + STR_TO_CODE_ELIF(2, 0x3a, KB_M) -+ STR_TO_CODE_ELIF(2, 0x41, KB_COMA) ++ STR_TO_CODE_ELIF(2, 0x41, KB_COMMA) + STR_TO_CODE_ELIF(2, 0x49, KB_PERIOD) + STR_TO_CODE_ELIF(2, 0x4a, KB_FWDSLASH) + STR_TO_CODE_ELIF(2, 0x89, KB_RSHIFT) @@ -509,9 +509,9 @@ index 000000000000..f0a2b366a298 + STR_TO_CODE_ELIF(2, 0x91, KB_LEFT_ARROW) + STR_TO_CODE_ELIF(2, 0x9b, KB_RIGHT_ARROW) + -+ STR_TO_CODE_ELIF(2, 0x77, NUMPAD_LCK) ++ STR_TO_CODE_ELIF(2, 0x77, NUMPAD_LOCK) + STR_TO_CODE_ELIF(2, 0x90, NUMPAD_FWDSLASH) -+ STR_TO_CODE_ELIF(2, 0x7c, NUMPAD_STAR) ++ STR_TO_CODE_ELIF(2, 0x7c, NUMPAD_ASTERISK) + STR_TO_CODE_ELIF(2, 0x7b, NUMPAD_HYPHEN) + STR_TO_CODE_ELIF(2, 0x70, NUMPAD_0) + STR_TO_CODE_ELIF(2, 0x69, NUMPAD_1) @@ -664,7 +664,7 @@ index 000000000000..f0a2b366a298 + CODE_TO_STR_IF(2, 0x32, KB_B) + CODE_TO_STR_IF(2, 0x31, KB_N) + CODE_TO_STR_IF(2, 0x3a, KB_M) -+ CODE_TO_STR_IF(2, 0x41, KB_COMA) ++ CODE_TO_STR_IF(2, 0x41, KB_COMMA) + CODE_TO_STR_IF(2, 0x49, KB_PERIOD) + CODE_TO_STR_IF(2, 0x4a, KB_FWDSLASH) + CODE_TO_STR_IF(2, 0x89, KB_RSHIFT) @@ -692,9 +692,9 @@ index 000000000000..f0a2b366a298 + CODE_TO_STR_IF(2, 0x91, KB_LEFT_ARROW) + CODE_TO_STR_IF(2, 0x9b, KB_RIGHT_ARROW) + -+ CODE_TO_STR_IF(2, 0x77, NUMPAD_LCK) ++ CODE_TO_STR_IF(2, 0x77, NUMPAD_LOCK) + CODE_TO_STR_IF(2, 0x90, NUMPAD_FWDSLASH) -+ CODE_TO_STR_IF(2, 0x7c, NUMPAD_STAR) ++ CODE_TO_STR_IF(2, 0x7c, NUMPAD_ASTERISK) + CODE_TO_STR_IF(2, 0x7b, NUMPAD_HYPHEN) + CODE_TO_STR_IF(2, 0x70, NUMPAD_0) + CODE_TO_STR_IF(2, 0x69, NUMPAD_1) @@ -738,36 +738,38 @@ index 000000000000..f0a2b366a298 +static int __gamepad_check_ready(struct hid_device *hdev) +{ + u8 *hidbuf; -+ int ret; ++ int ret, count; + + hidbuf = kzalloc(FEATURE_ROG_ALLY_REPORT_SIZE, GFP_KERNEL); + if (!hidbuf) + return -ENOMEM; + -+ hidbuf[0] = FEATURE_KBD_REPORT_ID; -+ hidbuf[1] = 0xD1; -+ hidbuf[2] = xpad_cmd_check_ready; -+ hidbuf[3] = 01; -+ ret = asus_kbd_set_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE); -+ if (ret < 0) -+ goto report_fail; -+ -+ hidbuf[0] = hidbuf[1] = hidbuf[2] = hidbuf[3] = 0; -+ ret = asus_kbd_get_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE); -+ if (ret < 0) -+ goto report_fail; -+ -+ ret = hidbuf[2] == xpad_cmd_check_ready; -+ if (!ret) { -+ hid_warn(hdev, "ROG Ally not ready\n"); -+ ret = -ENOMSG; ++ for (count = 0; count < 3; count++) { ++ hidbuf[0] = FEATURE_KBD_REPORT_ID; ++ hidbuf[1] = 0xD1; ++ hidbuf[2] = xpad_cmd_check_ready; ++ hidbuf[3] = 01; ++ ret = asus_kbd_set_report(hdev, hidbuf, ++ FEATURE_ROG_ALLY_REPORT_SIZE); ++ if (ret < 0) ++ hid_warn(hdev, "ROG Ally check failed set report: %d\n", ret); ++ ++ hidbuf[0] = hidbuf[1] = hidbuf[2] = hidbuf[3] = 0; ++ ret = asus_kbd_get_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE); ++ if (ret < 0) ++ hid_warn(hdev, "ROG Ally check failed get report: %d\n", ret); ++ ++ ret = hidbuf[2] == xpad_cmd_check_ready; ++ if (!ret) ++ hid_warn(hdev, "ROG Ally not ready, retry %d\n", count); ++ else ++ break; ++ msleep(2); // don't spam the entire loop in less than USB response time + } + -+ kfree(hidbuf); -+ return ret; ++ if (count == 3) ++ hid_err(hdev, "ROG Ally never responded with a ready\n"); + -+report_fail: -+ hid_dbg(hdev, "ROG Ally check failed get report: %d\n", ret); + kfree(hidbuf); + return ret; +} @@ -841,7 +843,7 @@ index 000000000000..f0a2b366a298 +static int __gamepad_turbo_show(struct device *raw_dev, enum btn_pair pair, int side) +{ + struct asus_rog_ally *rog_ally = __rog_ally_data(raw_dev); -+ return rog_ally->turbo_btns[rog_ally->mode][__gamepad_turbo_index(pair, side)]; ++ return rog_ally->turbo_btns[rog_ally->mode - 1][__gamepad_turbo_index(pair, side)]; +}; + +static int __gamepad_turbo_store(struct device *raw_dev, const char *buf, enum btn_pair pair, @@ -856,7 +858,7 @@ index 000000000000..f0a2b366a298 + if (val < 0 || val > 16) + return -EINVAL; + -+ rog_ally->turbo_btns[rog_ally->mode][__gamepad_turbo_index(pair, side)] = val; ++ rog_ally->turbo_btns[rog_ally->mode - 1][__gamepad_turbo_index(pair, side)] = val; + + return 0; +}; @@ -949,6 +951,10 @@ index 000000000000..f0a2b366a298 + hidbuf[3] = 0x01; + hidbuf[4] = val; + ++ ret = __gamepad_check_ready(hdev); ++ if (ret < 0) ++ goto report_fail; ++ + ret = asus_kbd_set_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE); + if (ret < 0) + goto report_fail; @@ -1020,8 +1026,8 @@ index 000000000000..f0a2b366a298 + hidbuf[1] = 0xD1; + hidbuf[2] = xpad_cmd_set_vibe_intensity; + hidbuf[3] = 0x02; // length -+ hidbuf[4] = rog_ally->anti_deadzones[rog_ally->mode][btn_pair_side_left]; -+ hidbuf[5] = rog_ally->anti_deadzones[rog_ally->mode][btn_pair_side_right]; ++ hidbuf[4] = rog_ally->vibration_intensity[rog_ally->mode - 1][btn_pair_side_left]; ++ hidbuf[5] = rog_ally->vibration_intensity[rog_ally->mode - 1][btn_pair_side_right]; + + ret = __gamepad_check_ready(hdev); + if (ret < 0) @@ -1041,8 +1047,8 @@ index 000000000000..f0a2b366a298 +{ + struct asus_rog_ally *rog_ally = __rog_ally_data(raw_dev); + return sysfs_emit(buf, "%d %d\n", -+ rog_ally->anti_deadzones[rog_ally->mode][btn_pair_side_left], -+ rog_ally->anti_deadzones[rog_ally->mode][btn_pair_side_right]); ++ rog_ally->vibration_intensity[rog_ally->mode - 1][btn_pair_side_left], ++ rog_ally->vibration_intensity[rog_ally->mode - 1][btn_pair_side_right]); +} + +static ssize_t gamepad_vibration_intensity_store(struct device *raw_dev, @@ -1051,6 +1057,7 @@ index 000000000000..f0a2b366a298 +{ + struct asus_rog_ally *rog_ally = __rog_ally_data(raw_dev); + u32 left, right; ++ int ret; + + if (sscanf(buf, "%d %d", &left, &right) != 2) + return -EINVAL; @@ -1058,8 +1065,12 @@ index 000000000000..f0a2b366a298 + if (left > 64 || right > 64) + return -EINVAL; + -+ rog_ally->vibration_intensity[rog_ally->mode][btn_pair_side_left] = left; -+ rog_ally->vibration_intensity[rog_ally->mode][btn_pair_side_right] = right; ++ rog_ally->vibration_intensity[rog_ally->mode - 1][btn_pair_side_left] = left; ++ rog_ally->vibration_intensity[rog_ally->mode - 1][btn_pair_side_right] = right; ++ ++ ret = __gamepad_write_vibe_intensity_to_mcu(raw_dev); ++ if (ret < 0) ++ return ret; + + return count; +} @@ -1098,20 +1109,20 @@ index 000000000000..f0a2b366a298 + hidbuf[1] = 0xD1; + hidbuf[2] = xpad_cmd_set_js_dz; + hidbuf[3] = 0x04; // length -+ hidbuf[4] = rog_ally->deadzones[rog_ally->mode][0][0]; -+ hidbuf[5] = rog_ally->deadzones[rog_ally->mode][0][1]; -+ hidbuf[6] = rog_ally->deadzones[rog_ally->mode][0][2]; -+ hidbuf[7] = rog_ally->deadzones[rog_ally->mode][0][3]; ++ hidbuf[4] = rog_ally->deadzones[rog_ally->mode - 1][0][0]; ++ hidbuf[5] = rog_ally->deadzones[rog_ally->mode - 1][0][1]; ++ hidbuf[6] = rog_ally->deadzones[rog_ally->mode - 1][0][2]; ++ hidbuf[7] = rog_ally->deadzones[rog_ally->mode - 1][0][3]; + + ret = asus_kbd_set_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE); + if (ret < 0) + goto end; + + hidbuf[2] = xpad_cmd_set_tr_dz; -+ hidbuf[4] = rog_ally->deadzones[rog_ally->mode][1][0]; -+ hidbuf[5] = rog_ally->deadzones[rog_ally->mode][1][1]; -+ hidbuf[6] = rog_ally->deadzones[rog_ally->mode][1][2]; -+ hidbuf[7] = rog_ally->deadzones[rog_ally->mode][1][3]; ++ hidbuf[4] = rog_ally->deadzones[rog_ally->mode - 1][1][0]; ++ hidbuf[5] = rog_ally->deadzones[rog_ally->mode - 1][1][1]; ++ hidbuf[6] = rog_ally->deadzones[rog_ally->mode - 1][1][2]; ++ hidbuf[7] = rog_ally->deadzones[rog_ally->mode - 1][1][3]; + + ret = asus_kbd_set_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE); + if (ret < 0) @@ -1139,8 +1150,8 @@ index 000000000000..f0a2b366a298 + side = axis == xpad_axis_xy_right || axis == xpad_axis_z_right ? 2 : 0; + cmd = is_tr ? xpad_cmd_set_js_dz : xpad_cmd_set_tr_dz; + -+ rog_ally->deadzones[rog_ally->mode][is_tr][side] = inner; -+ rog_ally->deadzones[rog_ally->mode][is_tr][side + 1] = outer; ++ rog_ally->deadzones[rog_ally->mode - 1][is_tr][side] = inner; ++ rog_ally->deadzones[rog_ally->mode - 1][is_tr][side + 1] = outer; + + return 0; +} @@ -1178,8 +1189,8 @@ index 000000000000..f0a2b366a298 + hidbuf[1] = 0xD1; + hidbuf[2] = xpad_cmd_set_adz; + hidbuf[3] = 0x02; // length -+ hidbuf[4] = rog_ally->anti_deadzones[rog_ally->mode][btn_pair_side_left]; -+ hidbuf[5] = rog_ally->anti_deadzones[rog_ally->mode][btn_pair_side_right]; ++ hidbuf[4] = rog_ally->anti_deadzones[rog_ally->mode - 1][btn_pair_side_left]; ++ hidbuf[5] = rog_ally->anti_deadzones[rog_ally->mode - 1][btn_pair_side_right]; + + ret = __gamepad_check_ready(hdev); + if (ret < 0) @@ -1204,10 +1215,10 @@ index 000000000000..f0a2b366a298 + if (ret) + return ret; + -+ if (val < 0 || val > 64) ++ if (val < 0 || val > 32) + return -EINVAL; + -+ rog_ally->anti_deadzones[rog_ally->mode][side] = val; ++ rog_ally->anti_deadzones[rog_ally->mode - 1][side] = val; + + return ret; +} @@ -1217,7 +1228,7 @@ index 000000000000..f0a2b366a298 +{ + struct asus_rog_ally *rog_ally = __rog_ally_data(raw_dev); + return sysfs_emit(buf, "%d\n", -+ rog_ally->anti_deadzones[rog_ally->mode][btn_pair_side_left]); ++ rog_ally->anti_deadzones[rog_ally->mode - 1][btn_pair_side_left]); +} + +static ssize_t xpad_axis_xy_left_ADZ_store(struct device *raw_dev, struct device_attribute *attr, @@ -1237,7 +1248,7 @@ index 000000000000..f0a2b366a298 +{ + struct asus_rog_ally *rog_ally = __rog_ally_data(raw_dev); + return sysfs_emit(buf, "%d\n", -+ rog_ally->anti_deadzones[rog_ally->mode][btn_pair_side_right]); ++ rog_ally->anti_deadzones[rog_ally->mode - 1][btn_pair_side_right]); +} + +static ssize_t xpad_axis_xy_right_ADZ_store(struct device *raw_dev, struct device_attribute *attr, @@ -1280,14 +1291,14 @@ index 000000000000..f0a2b366a298 + hidbuf[2] = xpad_cmd_set_response_curve; + hidbuf[3] = 0x09; // length + hidbuf[4] = 0x01; -+ memcpy(&hidbuf[5], &rog_ally->response_curve[rog_ally->mode][btn_pair_side_left], 8); ++ memcpy(&hidbuf[5], &rog_ally->response_curve[rog_ally->mode - 1][btn_pair_side_left], 8); + + ret = __gamepad_check_ready(hdev); + if (ret < 0) + goto report_fail; + + hidbuf[4] = 0x02; -+ memcpy(&hidbuf[5], &rog_ally->response_curve[rog_ally->mode][btn_pair_side_right], 8); ++ memcpy(&hidbuf[5], &rog_ally->response_curve[rog_ally->mode - 1][btn_pair_side_right], 8); + + ret = __gamepad_check_ready(hdev); + if (ret < 0) @@ -1315,8 +1326,8 @@ index 000000000000..f0a2b366a298 + if (move > 64 || response > 64) + return -EINVAL; + -+ rog_ally->response_curve[rog_ally->mode][side][idx] = move; -+ rog_ally->response_curve[rog_ally->mode][side][idx + 1] = response; ++ rog_ally->response_curve[rog_ally->mode - 1][side][idx] = move; ++ rog_ally->response_curve[rog_ally->mode - 1][side][idx + 1] = response; + + return 0; +} @@ -1361,10 +1372,7 @@ index 000000000000..f0a2b366a298 + c = &hidbuf[6]; // pointer + + for (size_t i = 0; i < data_len; i++) { -+ if (axis == xpad_axis_xy_left || axis == xpad_axis_xy_right) -+ cal = rog_ally->js_calibrations[side][i]; -+ else -+ cal = rog_ally->tr_calibrations[side][i]; ++ cal = rog_ally->js_calibrations[side][i]; + *c = (u8)((cal & 0xff00) >> 8); + checksum += *c; + c += 1; @@ -1428,6 +1436,7 @@ index 000000000000..f0a2b366a298 + //TODO: validate input + + side = axis == xpad_axis_xy_right || axis == xpad_axis_z_right ? 1 : 0; ++ /* stored in reverse order for easy copy to packet */ + rog_ally->tr_calibrations[side][0] = x_stable; + rog_ally->tr_calibrations[side][1] = x_max; + @@ -1663,7 +1672,7 @@ index 000000000000..f0a2b366a298 + hidbuf[1] = 0xD1; + hidbuf[2] = xpad_cmd_set_turbo; + hidbuf[3] = 0x20; // length -+ memcpy(&hidbuf[4], rog_ally->turbo_btns[rog_ally->mode], TURBO_BLOCK_LEN); ++ memcpy(&hidbuf[4], rog_ally->turbo_btns[rog_ally->mode - 1], TURBO_BLOCK_LEN); + ret = asus_kbd_set_report(hdev, hidbuf, FEATURE_ROG_ALLY_REPORT_SIZE); + + kfree(hidbuf); @@ -1673,7 +1682,7 @@ index 000000000000..f0a2b366a298 +static int asus_rog_ally_probe(struct hid_device *hdev, const struct rog_ops *ops) +{ + struct asus_drvdata *drvdata = hid_get_drvdata(hdev); -+ int ret; ++ int ret = 0; + + /* all ROG devices have this HID interface but we will focus on Ally for now */ + if (drvdata->quirks & QUIRK_ROG_NKEY_KEYBOARD && hid_is_usb(hdev)) { @@ -1697,41 +1706,44 @@ index 000000000000..f0a2b366a298 + } + // TODO: move these to functions + drvdata->rog_ally_data->mode = xpad_mode_game; -+ drvdata->rog_ally_data->deadzones[xpad_mode_game][0][1] = 64; -+ drvdata->rog_ally_data->deadzones[xpad_mode_game][0][3] = 64; -+ drvdata->rog_ally_data->deadzones[xpad_mode_game][1][1] = 64; -+ drvdata->rog_ally_data->deadzones[xpad_mode_game][1][3] = 64; -+ -+ drvdata->rog_ally_data->anti_deadzones[xpad_mode_game][0] = 64; -+ drvdata->rog_ally_data->anti_deadzones[xpad_mode_game][1] = 64; -+ -+ drvdata->rog_ally_data->response_curve[xpad_mode_game][0][0] = 0x14; -+ drvdata->rog_ally_data->response_curve[xpad_mode_game][0][1] = 0x14; -+ drvdata->rog_ally_data->response_curve[xpad_mode_game][0][2] = 0x28; -+ drvdata->rog_ally_data->response_curve[xpad_mode_game][0][3] = 0x28; -+ drvdata->rog_ally_data->response_curve[xpad_mode_game][0][4] = 0x3c; -+ drvdata->rog_ally_data->response_curve[xpad_mode_game][0][5] = 0x3c; -+ drvdata->rog_ally_data->response_curve[xpad_mode_game][0][6] = 0x50; -+ drvdata->rog_ally_data->response_curve[xpad_mode_game][0][7] = 0x50; -+ -+ drvdata->rog_ally_data->response_curve[xpad_mode_game][1][0] = 0x14; -+ drvdata->rog_ally_data->response_curve[xpad_mode_game][1][1] = 0x14; -+ drvdata->rog_ally_data->response_curve[xpad_mode_game][1][2] = 0x28; -+ drvdata->rog_ally_data->response_curve[xpad_mode_game][1][3] = 0x28; -+ drvdata->rog_ally_data->response_curve[xpad_mode_game][1][4] = 0x3c; -+ drvdata->rog_ally_data->response_curve[xpad_mode_game][1][5] = 0x3c; -+ drvdata->rog_ally_data->response_curve[xpad_mode_game][1][6] = 0x50; -+ drvdata->rog_ally_data->response_curve[xpad_mode_game][1][7] = 0x50; ++ for (int i = 0; i < xpad_mode_mouse; i++) { ++ drvdata->rog_ally_data->deadzones[i][0][1] = 64; ++ drvdata->rog_ally_data->deadzones[i][0][3] = 64; ++ drvdata->rog_ally_data->deadzones[i][1][1] = 64; ++ drvdata->rog_ally_data->deadzones[i][1][3] = 64; ++ ++ drvdata->rog_ally_data->response_curve[i][0][0] = 0x14; ++ drvdata->rog_ally_data->response_curve[i][0][1] = 0x14; ++ drvdata->rog_ally_data->response_curve[i][0][2] = 0x28; ++ drvdata->rog_ally_data->response_curve[i][0][3] = 0x28; ++ drvdata->rog_ally_data->response_curve[i][0][4] = 0x3c; ++ drvdata->rog_ally_data->response_curve[i][0][5] = 0x3c; ++ drvdata->rog_ally_data->response_curve[i][0][6] = 0x50; ++ drvdata->rog_ally_data->response_curve[i][0][7] = 0x50; ++ ++ drvdata->rog_ally_data->response_curve[i][1][0] = 0x14; ++ drvdata->rog_ally_data->response_curve[i][1][1] = 0x14; ++ drvdata->rog_ally_data->response_curve[i][1][2] = 0x28; ++ drvdata->rog_ally_data->response_curve[i][1][3] = 0x28; ++ drvdata->rog_ally_data->response_curve[i][1][4] = 0x3c; ++ drvdata->rog_ally_data->response_curve[i][1][5] = 0x3c; ++ drvdata->rog_ally_data->response_curve[i][1][6] = 0x50; ++ drvdata->rog_ally_data->response_curve[i][1][7] = 0x50; ++ ++ drvdata->rog_ally_data->vibration_intensity[i][0] = 64; ++ drvdata->rog_ally_data->vibration_intensity[i][1] = 64; ++ } + ++ /* ignore all errors for this as they are related to USB HID I/O */ + __gamepad_mapping_xpad_default(drvdata->rog_ally_data); ++ __gamepad_mapping_wasd_default(drvdata->rog_ally_data); + // these calls will never error so ignore the return + __gamepad_mapping_store(&hdev->dev, "kb_f14", btn_pair_m1_m2, + btn_pair_side_left, false); // M2 + __gamepad_mapping_store(&hdev->dev, "kb_f15", btn_pair_m1_m2, + btn_pair_side_right, false); // M1 -+ ret = __gamepad_set_mode(&hdev->dev, xpad_mode_game); -+ if (ret < 0) -+ return ret; ++ __gamepad_set_mapping(&hdev->dev, btn_pair_m1_m2); ++ __gamepad_set_mode(&hdev->dev, xpad_mode_game); + } + + if (sysfs_create_groups(&hdev->dev.kobj, gamepad_device_attr_groups)) @@ -1760,7 +1772,7 @@ index 000000000000..f0a2b366a298 +}; diff --git a/drivers/hid/hid-asus-rog.h b/drivers/hid/hid-asus-rog.h new file mode 100644 -index 000000000000..4d81f0ce8c59 +index 000000000000..efad0b041d5d --- /dev/null +++ b/drivers/hid/hid-asus-rog.h @@ -0,0 +1,482 @@ @@ -1816,7 +1828,7 @@ index 000000000000..4d81f0ce8c59 +#define KB_F14 "kb_f14" +#define KB_F15 "kb_f15" + -+#define KB_BACKTICK "kb_`" ++#define KB_BACKTICK "kb_backtick" +#define KB_1 "kb_1" +#define KB_2 "kb_2" +#define KB_3 "kb_3" @@ -1827,8 +1839,8 @@ index 000000000000..4d81f0ce8c59 +#define KB_8 "kb_8" +#define KB_9 "kb_9" +#define KB_0 "kb_0" -+#define KB_HYPHEN "kb_-" -+#define KB_EQUALS "kb_=" ++#define KB_HYPHEN "kb_hyphen" ++#define KB_EQUALS "kb_equals" +#define KB_BACKSPACE "kb_backspace" + +#define KB_TAB "kb_tab" @@ -1842,8 +1854,8 @@ index 000000000000..4d81f0ce8c59 +#define KB_I "kb_i" +#define KB_O "kb_o" +#define KB_P "kb_p" -+#define KB_LBRACKET "kb_[" -+#define KB_RBRACKET "kb_]" ++#define KB_LBRACKET "kb_lbracket" ++#define KB_RBRACKET "kb_rbracket" +#define KB_BACKSLASH "kb_bkslash" + +#define KB_CAPS "kb_caps" @@ -1856,8 +1868,8 @@ index 000000000000..4d81f0ce8c59 +#define KB_J "kb_j" +#define KB_K "kb_k" +#define KB_L "kb_l" -+#define KB_SEMI "kb_;" -+#define KB_QUOTE "kb_'" ++#define KB_SEMI "kb_semicolon" ++#define KB_QUOTE "kb_quote" +#define KB_RET "kb_enter" + +#define KB_LSHIFT "kb_lshift" @@ -1868,9 +1880,9 @@ index 000000000000..4d81f0ce8c59 +#define KB_B "kb_b" +#define KB_N "kb_n" +#define KB_M "kb_m" -+#define KB_COMA "kb_," -+#define KB_PERIOD "kb_." -+#define KB_FWDSLASH "kb_/" ++#define KB_COMMA "kb_comma" ++#define KB_PERIOD "kb_period" ++#define KB_FWDSLASH "kb_fwdslash" +#define KB_RSHIFT "kb_rshift" + +#define KB_LCTL "kb_lctl" @@ -1896,10 +1908,10 @@ index 000000000000..4d81f0ce8c59 +#define KB_LEFT_ARROW "kb_left_arrow" +#define KB_RIGHT_ARROW "kb_right_arrow" + -+#define NUMPAD_LCK "numpad_lck" -+#define NUMPAD_FWDSLASH "numpad_/" -+#define NUMPAD_STAR "numpad_*" -+#define NUMPAD_HYPHEN "numpad_-" ++#define NUMPAD_LOCK "numpad_lock" ++#define NUMPAD_FWDSLASH "numpad_fwdslash" ++#define NUMPAD_ASTERISK "numpad_asterisk" ++#define NUMPAD_HYPHEN "numpad_hyphen" +#define NUMPAD_0 "numpad_0" +#define NUMPAD_1 "numpad_1" +#define NUMPAD_2 "numpad_2" @@ -1910,7 +1922,7 @@ index 000000000000..4d81f0ce8c59 +#define NUMPAD_7 "numpad_7" +#define NUMPAD_8 "numpad_8" +#define NUMPAD_9 "numpad_9" -+#define NUMPAD_PLUS "numpad_+" ++#define NUMPAD_PLUS "numpad_plus" +#define NUMPAD_ENTER "numpad_enter" +#define NUMPAD_PERIOD "numpad_." + @@ -2193,12 +2205,17 @@ index 000000000000..4d81f0ce8c59 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + ++/* ++ * the xpad_mode is used inside the mode setting packet and is used ++ * for indexing (xpad_mode - 1) ++ */ +enum xpad_mode { + xpad_mode_game = 0x01, + xpad_mode_wasd = 0x02, + xpad_mode_mouse = 0x03, +}; + ++/* the xpad_cmd determines which feature is set or queried */ +enum xpad_cmd { + xpad_cmd_set_mode = 0x01, + xpad_cmd_set_mapping = 0x02, @@ -2212,6 +2229,10 @@ index 000000000000..4d81f0ce8c59 + xpad_cmd_set_adz = 0x18, +}; + ++/* ++ * the xpad_mode is used in various set and query HID packets and is ++ * used for indexing (xpad_axis - 1) ++ */ +enum xpad_axis { + xpad_axis_xy_left = 0x01, + xpad_axis_xy_right = 0x02, @@ -2219,15 +2240,6 @@ index 000000000000..4d81f0ce8c59 + xpad_axis_z_right = 0x04, +}; + -+enum mcu_output_dev { -+ mcu_output_dev_blank = 0x00, -+ mcu_output_dev_xpad = 0x01, -+ mcu_output_dev_keyboard = 0x02, -+ mcu_output_dev_mouse = 0x03, -+ mcu_output_dev_macro = 0x04, -+ mcu_output_dev_media = 0x05, -+}; -+ +enum btn_pair { + btn_pair_dpad_u_d = 0x01, + btn_pair_dpad_l_r = 0x02, @@ -2313,5 +2325,5 @@ index 000000000000..18317cad7110 +extern const struct rog_ops rog_ally; \ No newline at end of file -- -2.41.0 +2.43.0 diff --git a/wifi-cfg80211-fix-cqm-for-non-range-use.patch b/wifi-cfg80211-fix-cqm-for-non-range-use.patch new file mode 100644 index 000000000000..933cea1700a8 --- /dev/null +++ b/wifi-cfg80211-fix-cqm-for-non-range-use.patch @@ -0,0 +1,141 @@ +From 7e7efdda6adb385fbdfd6f819d76bc68c923c394 Mon Sep 17 00:00:00 2001 +From: Johannes Berg <johannes.berg@intel.com> +Date: Mon, 6 Nov 2023 23:17:16 +0100 +Subject: wifi: cfg80211: fix CQM for non-range use + +From: Johannes Berg <johannes.berg@intel.com> + +commit 7e7efdda6adb385fbdfd6f819d76bc68c923c394 upstream. + +My prior race fix here broke CQM when ranges aren't used, as +the reporting worker now requires the cqm_config to be set in +the wdev, but isn't set when there's no range configured. + +Rather than continuing to special-case the range version, set +the cqm_config always and configure accordingly, also tracking +if range was used or not to be able to clear the configuration +appropriately with the same API, which was actually not right +if both were implemented by a driver for some reason, as is +the case with mac80211 (though there the implementations are +equivalent so it doesn't matter.) + +Also, the original multiple-RSSI commit lost checking for the +callback, so might have potentially crashed if a driver had +neither implementation, and userspace tried to use it despite +not being advertised as supported. + +Cc: stable@vger.kernel.org +Fixes: 4a4b8169501b ("cfg80211: Accept multiple RSSI thresholds for CQM") +Fixes: 37c20b2effe9 ("wifi: cfg80211: fix cqm_config access race") +Signed-off-by: Johannes Berg <johannes.berg@intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + net/wireless/core.h | 1 + net/wireless/nl80211.c | 50 ++++++++++++++++++++++++++++++------------------- + 2 files changed, 32 insertions(+), 19 deletions(-) + +--- a/net/wireless/core.h ++++ b/net/wireless/core.h +@@ -299,6 +299,7 @@ struct cfg80211_cqm_config { + u32 rssi_hyst; + s32 last_rssi_event_value; + enum nl80211_cqm_rssi_threshold_event last_rssi_event_type; ++ bool use_range_api; + int n_rssi_thresholds; + s32 rssi_thresholds[] __counted_by(n_rssi_thresholds); + }; +--- a/net/wireless/nl80211.c ++++ b/net/wireless/nl80211.c +@@ -12824,10 +12824,6 @@ static int cfg80211_cqm_rssi_update(stru + int i, n, low_index; + int err; + +- /* RSSI reporting disabled? */ +- if (!cqm_config) +- return rdev_set_cqm_rssi_range_config(rdev, dev, 0, 0); +- + /* + * Obtain current RSSI value if possible, if not and no RSSI threshold + * event has been received yet, we should receive an event after a +@@ -12902,18 +12898,6 @@ static int nl80211_set_cqm_rssi(struct g + wdev->iftype != NL80211_IFTYPE_P2P_CLIENT) + return -EOPNOTSUPP; + +- if (n_thresholds <= 1 && rdev->ops->set_cqm_rssi_config) { +- if (n_thresholds == 0 || thresholds[0] == 0) /* Disabling */ +- return rdev_set_cqm_rssi_config(rdev, dev, 0, 0); +- +- return rdev_set_cqm_rssi_config(rdev, dev, +- thresholds[0], hysteresis); +- } +- +- if (!wiphy_ext_feature_isset(&rdev->wiphy, +- NL80211_EXT_FEATURE_CQM_RSSI_LIST)) +- return -EOPNOTSUPP; +- + if (n_thresholds == 1 && thresholds[0] == 0) /* Disabling */ + n_thresholds = 0; + +@@ -12921,6 +12905,20 @@ static int nl80211_set_cqm_rssi(struct g + old = rcu_dereference_protected(wdev->cqm_config, + lockdep_is_held(&wdev->mtx)); + ++ /* if already disabled just succeed */ ++ if (!n_thresholds && !old) ++ return 0; ++ ++ if (n_thresholds > 1) { ++ if (!wiphy_ext_feature_isset(&rdev->wiphy, ++ NL80211_EXT_FEATURE_CQM_RSSI_LIST) || ++ !rdev->ops->set_cqm_rssi_range_config) ++ return -EOPNOTSUPP; ++ } else { ++ if (!rdev->ops->set_cqm_rssi_config) ++ return -EOPNOTSUPP; ++ } ++ + if (n_thresholds) { + cqm_config = kzalloc(struct_size(cqm_config, rssi_thresholds, + n_thresholds), +@@ -12935,13 +12933,26 @@ static int nl80211_set_cqm_rssi(struct g + memcpy(cqm_config->rssi_thresholds, thresholds, + flex_array_size(cqm_config, rssi_thresholds, + n_thresholds)); ++ cqm_config->use_range_api = n_thresholds > 1 || ++ !rdev->ops->set_cqm_rssi_config; + + rcu_assign_pointer(wdev->cqm_config, cqm_config); ++ ++ if (cqm_config->use_range_api) ++ err = cfg80211_cqm_rssi_update(rdev, dev, cqm_config); ++ else ++ err = rdev_set_cqm_rssi_config(rdev, dev, ++ thresholds[0], ++ hysteresis); + } else { + RCU_INIT_POINTER(wdev->cqm_config, NULL); ++ /* if enabled as range also disable via range */ ++ if (old->use_range_api) ++ err = rdev_set_cqm_rssi_range_config(rdev, dev, 0, 0); ++ else ++ err = rdev_set_cqm_rssi_config(rdev, dev, 0, 0); + } + +- err = cfg80211_cqm_rssi_update(rdev, dev, cqm_config); + if (err) { + rcu_assign_pointer(wdev->cqm_config, old); + kfree_rcu(cqm_config, rcu_head); +@@ -19131,10 +19142,11 @@ void cfg80211_cqm_rssi_notify_work(struc + wdev_lock(wdev); + cqm_config = rcu_dereference_protected(wdev->cqm_config, + lockdep_is_held(&wdev->mtx)); +- if (!wdev->cqm_config) ++ if (!cqm_config) + goto unlock; + +- cfg80211_cqm_rssi_update(rdev, wdev->netdev, cqm_config); ++ if (cqm_config->use_range_api) ++ cfg80211_cqm_rssi_update(rdev, wdev->netdev, cqm_config); + + rssi_level = cqm_config->last_rssi_event_value; + rssi_event = cqm_config->last_rssi_event_type; diff --git a/wifi-nl80211-fix-deadlock-in-nl80211_set_cqm_rssi-(6.6.x).patch b/wifi-nl80211-fix-deadlock-in-nl80211_set_cqm_rssi-6.6.x.patch index 372271120e30..372271120e30 100644 --- a/wifi-nl80211-fix-deadlock-in-nl80211_set_cqm_rssi-(6.6.x).patch +++ b/wifi-nl80211-fix-deadlock-in-nl80211_set_cqm_rssi-6.6.x.patch |