From 79e741c9ecc9ede5758ec787e610be72a0292b12 Mon Sep 17 00:00:00 2001 From: Liang Chen Date: Wed, 11 Dec 2024 19:41:42 +0800 Subject: [PATCH 01/15] nvmem: rockchip-otp: reduce otp size to remove non-ecc area for rk3506 OTP[120]-OTP[127] is used with no ecc, so when read nvmem, it will cause the following error: rk3506-buildroot:/sys/bus/nvmem/devices/rockchip-otp0# busybox hexdump nvmem [ 38.601435] rockchip-otp ff4f0000.otp: ecc check error during read setup hexdump: nvmem: Input/output error Change-Id: Ia2d0aa892c75aa09fd3d4b1d65576f5313a765c4 Signed-off-by: Liang Chen --- drivers/nvmem/rockchip-otp.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/nvmem/rockchip-otp.c b/drivers/nvmem/rockchip-otp.c index 001ceee5673e..d5c5d6658f8b 100644 --- a/drivers/nvmem/rockchip-otp.c +++ b/drivers/nvmem/rockchip-otp.c @@ -769,6 +769,13 @@ static const char * const rk3528_otp_clocks[] = { "usr", "sbpi", "apb", }; +static const struct rockchip_data rk3506_data = { + .size = 0x78, + .clocks = rk3528_otp_clocks, + .num_clks = ARRAY_SIZE(rk3528_otp_clocks), + .reg_read = rk3568_otp_read, +}; + static const struct rockchip_data rk3528_data = { .size = 0x80, .clocks = rk3528_otp_clocks, @@ -870,7 +877,7 @@ static const struct of_device_id rockchip_otp_match[] = { #ifdef CONFIG_CPU_RK3506 { .compatible = "rockchip,rk3506-otp", - .data = (void *)&rk3528_data, + .data = (void *)&rk3506_data, }, #endif #ifdef CONFIG_CPU_RK3528 From e8a650f81333e806680c4a8b656e2bdd2e081c93 Mon Sep 17 00:00:00 2001 From: Sandy Huang Date: Wed, 10 Jul 2024 10:40:47 +0800 Subject: [PATCH 02/15] drm/rockchip: vop2: fix XRGB format alpha overlay error Some application draw XRGB format the X value may be not 0xff, If transfer this value to next level mix will appear overlay error. Signed-off-by: Sandy Huang Change-Id: I16d0e848325acefc4c0ab950d7bddaec82231cc1 --- drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index 2ea810647d04..9598b4624cee 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -10362,10 +10362,12 @@ static void vop2_parse_alpha(struct vop2_alpha_config *alpha_config, alpha->src_alpha_ctrl.bits.factor_mode = ALPHA_ONE; alpha->dst_alpha_ctrl.bits.alpha_mode = ALPHA_STRAIGHT; - if (alpha_config->dst_pixel_alpha_en && !dst_glb_alpha_en) + if (alpha_config->dst_pixel_alpha_en && dst_glb_alpha_en) + alpha->dst_alpha_ctrl.bits.blend_mode = ALPHA_PER_PIX_GLOBAL; + else if (alpha_config->dst_pixel_alpha_en && !dst_glb_alpha_en) alpha->dst_alpha_ctrl.bits.blend_mode = ALPHA_PER_PIX; else - alpha->dst_alpha_ctrl.bits.blend_mode = ALPHA_PER_PIX_GLOBAL; + alpha->dst_alpha_ctrl.bits.blend_mode = ALPHA_GLOBAL; alpha->dst_alpha_ctrl.bits.alpha_cal_mode = ALPHA_NO_SATURATION; alpha->dst_alpha_ctrl.bits.factor_mode = ALPHA_SRC_INVERSE; } @@ -10405,7 +10407,7 @@ static void vop2_setup_cluster_alpha(struct vop2 *vop2, struct vop2_cluster *clu struct vop2_plane_state *sub_vpstate; struct vop2_plane_state *top_win_vpstate; struct vop2_plane_state *bottom_win_vpstate; - bool src_pixel_alpha_en = false; + bool src_pixel_alpha_en = false, dst_pixel_alpha_en = false; u16 src_glb_alpha_val = 0xff, dst_glb_alpha_val = 0xff; bool premulti_en = false; bool swap = false; @@ -10456,10 +10458,11 @@ static void vop2_setup_cluster_alpha(struct vop2 *vop2, struct vop2_cluster *clu fb = bottom_win_vpstate->base.fb; if (!fb) return; + dst_pixel_alpha_en = is_alpha_support(fb->format->format); alpha_config.src_premulti_en = premulti_en; alpha_config.dst_premulti_en = false; alpha_config.src_pixel_alpha_en = src_pixel_alpha_en; - alpha_config.dst_pixel_alpha_en = true; /* alpha value need transfer to next mix */ + alpha_config.dst_pixel_alpha_en = dst_pixel_alpha_en; /* alpha value need transfer to next mix */ alpha_config.src_glb_alpha_value = src_glb_alpha_val; alpha_config.dst_glb_alpha_value = dst_glb_alpha_val; vop2_parse_alpha(&alpha_config, &alpha); @@ -10702,7 +10705,8 @@ static void rk3576_extra_alpha(struct vop2_video_port *vp, const struct vop2_zpo vop2_writel(vop2, 0x500, 1);/* enable port0_extra_alpha_en */ } else { - alpha_config.dst_pixel_alpha_en = false; + /* alpha value need transfer to next mix, and the data from last mix is at bottom layer */ + alpha_config.dst_pixel_alpha_en = true; alpha_config.dst_premulti_en = false; alpha_config.src_pixel_alpha_en = false; alpha_config.src_glb_alpha_value = 0xff; From 5d173bd0288548f5bc8192fc53886a5cf8ac7cd9 Mon Sep 17 00:00:00 2001 From: HangYu Li Date: Thu, 17 Oct 2024 10:32:31 +0800 Subject: [PATCH 03/15] iio: imu: inv_icm42670: add core of new inv_icm42670 driver 1. Core component of a new driver for InvenSense ICM-42670 devices. It includes registers definition, main probe/setup, and device utility functions. 2. Add SPI driver for InvenSense ICM-42670 devices. 3. Add I2C driver for InvenSense ICM-42670 devices. The ICM-42670-P is a high performance 6-axis MEMS MotionTracking device that combines a 3-axis gyroscope and a 3-axis accelerometer. It has a configurable host interface that supports I3CSM, I2C, and SPI serial communication, features up to 2.25 Kbytes FIFO and 2 programmable interrupts with ultra-lowpower wake-on-motion support to minimize system power consumption Change-Id: Ic308640f989ba6391eacca36f898dfc964054056 Signed-off-by: HangYu Li --- drivers/iio/imu/Kconfig | 1 + drivers/iio/imu/Makefile | 1 + drivers/iio/imu/inv_icm42670/Kconfig | 29 + drivers/iio/imu/inv_icm42670/Makefile | 12 + drivers/iio/imu/inv_icm42670/inv_icm42670.h | 559 ++++++++ .../iio/imu/inv_icm42670/inv_icm42670_core.c | 1122 +++++++++++++++++ .../iio/imu/inv_icm42670/inv_icm42670_i2c.c | 95 ++ .../iio/imu/inv_icm42670/inv_icm42670_ring.c | 244 ++++ .../iio/imu/inv_icm42670/inv_icm42670_spi.c | 90 ++ .../imu/inv_icm42670/inv_icm42670_trigger.c | 125 ++ 10 files changed, 2278 insertions(+) create mode 100644 drivers/iio/imu/inv_icm42670/Kconfig create mode 100644 drivers/iio/imu/inv_icm42670/Makefile create mode 100644 drivers/iio/imu/inv_icm42670/inv_icm42670.h create mode 100644 drivers/iio/imu/inv_icm42670/inv_icm42670_core.c create mode 100644 drivers/iio/imu/inv_icm42670/inv_icm42670_i2c.c create mode 100644 drivers/iio/imu/inv_icm42670/inv_icm42670_ring.c create mode 100644 drivers/iio/imu/inv_icm42670/inv_icm42670_spi.c create mode 100644 drivers/iio/imu/inv_icm42670/inv_icm42670_trigger.c diff --git a/drivers/iio/imu/Kconfig b/drivers/iio/imu/Kconfig index 3a18b1554a8d..8d6df41dcba3 100644 --- a/drivers/iio/imu/Kconfig +++ b/drivers/iio/imu/Kconfig @@ -94,6 +94,7 @@ config KMX61 be called kmx61. source "drivers/iio/imu/inv_icm42600/Kconfig" +source "drivers/iio/imu/inv_icm42670/Kconfig" source "drivers/iio/imu/inv_mpu6050/Kconfig" source "drivers/iio/imu/st_lsm6dsr/Kconfig" source "drivers/iio/imu/st_lsm6dsx/Kconfig" diff --git a/drivers/iio/imu/Makefile b/drivers/iio/imu/Makefile index f515b9bcaa43..f2cfa8828a07 100644 --- a/drivers/iio/imu/Makefile +++ b/drivers/iio/imu/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_FXOS8700_I2C) += fxos8700_i2c.o obj-$(CONFIG_FXOS8700_SPI) += fxos8700_spi.o obj-y += inv_icm42600/ +obj-y += inv_icm42670/ obj-y += inv_mpu6050/ obj-$(CONFIG_KMX61) += kmx61.o diff --git a/drivers/iio/imu/inv_icm42670/Kconfig b/drivers/iio/imu/inv_icm42670/Kconfig new file mode 100644 index 000000000000..e89c5281f6f8 --- /dev/null +++ b/drivers/iio/imu/inv_icm42670/Kconfig @@ -0,0 +1,29 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +config INV_ICM42670 + tristate + select IIO_BUFFER + +config INV_ICM42670_I2C + tristate "InvenSense ICM-42670 I2C driver" + depends on I2C + select INV_ICM42670 + select REGMAP_I2C + help + This driver supports the InvenSense ICM-426xx motion tracking + devices over I2C. + + This driver can be built as a module. The module will be called + inv-icm42670-i2c. + +config INV_ICM42670_SPI + tristate "InvenSense ICM-42670 SPI driver" + depends on SPI_MASTER + select INV_ICM42670 + select REGMAP_SPI + help + This driver supports the InvenSense ICM-426xx motion tracking + devices over SPI. + + This driver can be built as a module. The module will be called + inv-icm42670-spi. diff --git a/drivers/iio/imu/inv_icm42670/Makefile b/drivers/iio/imu/inv_icm42670/Makefile new file mode 100644 index 000000000000..cbad2768707f --- /dev/null +++ b/drivers/iio/imu/inv_icm42670/Makefile @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +obj-$(CONFIG_INV_ICM42670) += inv-icm42670.o +inv-icm42670-y += inv_icm42670_core.o +inv-icm42670-y += inv_icm42670_ring.o +inv-icm42670-y += inv_icm42670_trigger.o + +obj-$(CONFIG_INV_ICM42670_I2C) += inv-icm42670-i2c.o +inv-icm42670-i2c-y += inv_icm42670_i2c.o + +obj-$(CONFIG_INV_ICM42670_SPI) += inv-icm42670-spi.o +inv-icm42670-spi-y += inv_icm42670_spi.o diff --git a/drivers/iio/imu/inv_icm42670/inv_icm42670.h b/drivers/iio/imu/inv_icm42670/inv_icm42670.h new file mode 100644 index 000000000000..3aee90fafed4 --- /dev/null +++ b/drivers/iio/imu/inv_icm42670/inv_icm42670.h @@ -0,0 +1,559 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2024 Rockchip Electronics Co., Ltd. + */ + +#ifndef ICM42670_H_ +#define ICM42670_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Registers and associated bit definitions */ +/* Bank 0 */ +#define REG_MCLK_RDY 0x00 +#define REG_CHIP_CONFIG_REG 0x01 +#define REG_SIGNAL_PATH_RESET 0x02 +#define REG_DRIVE_CONFIG_REG1 0x03 +#define REG_DRIVE_CONFIG_REG2 0x04 +#define REG_DRIVE_CONFIG_REG3 0x05 +#define REG_INT_CONFIG_REG 0x06 +#define REG_TEMP_DATA0_UI 0x09 +#define REG_TEMP_DATA1_UI 0x0a +#define REG_ACCEL_DATA_X0_UI 0x0b +#define REG_ACCEL_DATA_X1_UI 0x0c +#define REG_ACCEL_DATA_Y0_UI 0x0d +#define REG_ACCEL_DATA_Y1_UI 0x0e +#define REG_ACCEL_DATA_Z0_UI 0x0f +#define REG_ACCEL_DATA_Z1_UI 0x10 +#define REG_GYRO_DATA_X0_UI 0x11 +#define REG_GYRO_DATA_X1_UI 0x12 +#define REG_GYRO_DATA_Y0_UI 0x13 +#define REG_GYRO_DATA_Y1_UI 0x14 +#define REG_GYRO_DATA_Z0_UI 0x15 +#define REG_GYRO_DATA_Z1_UI 0x16 +#define REG_TMST_FSYNC1 0x17 +#define REG_TMST_FSYNC2 0x18 +#define REG_APEX_DATA4 0x1d +#define REG_APEX_DATA5 0x1e +#define REG_PWR_MGMT_0 0x1f +#define REG_GYRO_CONFIG0 0x20 +#define REG_ACCEL_CONFIG0 0x21 +#define REG_TEMP_CONFIG0 0x22 +#define REG_GYRO_CONFIG1 0x23 +#define REG_ACCEL_CONFIG1 0x24 +#define REG_APEX_CONFIG0 0x25 +#define REG_APEX_CONFIG1 0x26 +#define REG_WOM_CONFIG 0x27 +#define REG_FIFO_CONFIG1 0x28 +#define REG_FIFO_CONFIG2 0x29 +#define REG_FIFO_CONFIG3 0x2a +#define REG_INT_SOURCE0 0x2b +#define REG_INT_SOURCE1 0x2c +#define REG_INT_SOURCE3 0x2d +#define REG_INT_SOURCE4 0x2e +#define REG_FIFO_LOST_PKT0 0x2f +#define REG_FIFO_LOST_PKT1 0x30 +#define REG_APEX_DATA0 0x31 +#define REG_APEX_DATA1 0x32 +#define REG_APEX_DATA2 0x33 +#define REG_APEX_DATA3 0x34 +#define REG_INTF_CONFIG0 0x35 +#define REG_INTF_CONFIG1 0x36 +#define REG_INT_STATUS_DRDY 0x39 +#define REG_INT_STATUS 0x3a +#define REG_INT_STATUS2 0x3b +#define REG_INT_STATUS3 0x3c +#define REG_FIFO_BYTE_COUNT1 0x3d +#define REG_FIFO_BYTE_COUNT2 0x3e +#define REG_FIFO_DATA_REG 0x3f +#define REG_WHO_AM_I 0x75 +#define REG_BLK_SEL_W 0x79 +#define REG_MADDR_W 0x7a +#define REG_M_W 0x7b +#define REG_BLK_SEL_R 0x7c +#define REG_MADDR_R 0x7d +#define REG_M_R 0x7e + +/* MREG_TOP1 */ +#define REG_TMST_CONFIG1_MREG_TOP1 0x00 +#define REG_FIFO_CONFIG5_MREG_TOP1 0x01 +#define REG_FIFO_CONFIG6_MREG_TOP1 0x02 +#define REG_FSYNC_CONFIG_MREG_TOP1 0x03 +#define REG_INT_CONFIG0_MREG_TOP1 0x04 +#define REG_INT_CONFIG1_MREG_TOP1 0x05 +#define REG_ST_CONFIG_MREG_TOP1 0x13 +#define REG_SELFTEST_MREG_TOP1 0x14 +#define REG_INTF_CONFIG6_MREG_TOP1 0x23 +#define REG_INTF_CONFIG10_MREG_TOP1 0x25 +#define REG_INTF_CONFIG7_MREG_TOP1 0x28 +#define REG_OTP_CONFIG_MREG_TOP1 0x2b +#define REG_INT_SOURCE6_MREG_TOP1 0x2f +#define REG_INT_SOURCE7_MREG_TOP1 0x30 +#define REG_INT_SOURCE8_MREG_TOP1 0x31 +#define REG_INT_SOURCE9_MREG_TOP1 0x32 +#define REG_APEX_CONFIG2_MREG_TOP1 0x44 +#define REG_APEX_CONFIG3_MREG_TOP1 0x45 +#define REG_APEX_CONFIG4_MREG_TOP1 0x46 +#define REG_APEX_CONFIG5_MREG_TOP1 0x47 +#define REG_APEX_CONFIG9_MREG_TOP1 0x48 +#define REG_APEX_CONFIG10_MREG_TOP1 0x49 +#define REG_APEX_CONFIG11_MREG_TOP1 0x4a +#define REG_ACCEL_WOM_X_THR_MREG_TOP1 0x4b +#define REG_ACCEL_WOM_Y_THR_MREG_TOP1 0x4c +#define REG_ACCEL_WOM_Z_THR_MREG_TOP1 0x4d +#define REG_GOS_USER0_MREG_TOP1 0x4e +#define REG_GOS_USER1_MREG_TOP1 0x4f +#define REG_GOS_USER2_MREG_TOP1 0x50 +#define REG_GOS_USER3_MREG_TOP1 0x51 +#define REG_GOS_USER4_MREG_TOP1 0x52 +#define REG_GOS_USER5_MREG_TOP1 0x53 +#define REG_GOS_USER6_MREG_TOP1 0x54 +#define REG_GOS_USER7_MREG_TOP1 0x55 +#define REG_GOS_USER8_MREG_TOP1 0x56 +#define REG_ST_STATUS1_MREG_TOP1 0x63 +#define REG_ST_STATUS2_MREG_TOP1 0x64 +#define REG_FDR_CONFIG_MREG_TOP1 0x66 +#define REG_APEX_CONFIG12_MREG_TOP1 0x67 + +/* MREG_TOP2 */ +#define REG_OTP_CTRL7_MREG_OTP_TOP2 0x2806 + +/* MREG_TOP3 */ +#define REG_XA_ST_DATA_MMEM_TOP3 0x5000 +#define REG_YA_ST_DATA_MMEM_TOP3 0x5001 +#define REG_ZA_ST_DATA_MMEM_TOP3 0x5002 +#define REG_XG_ST_DATA_MMEM_TOP3 0x5003 +#define REG_YG_ST_DATA_MMEM_TOP3 0x5004 +#define REG_ZG_ST_DATA_MMEM_TOP3 0x5005 + +/* Bank0 REG_GYRO_CONFIG0/REG_ACCEL_CONFIG0 */ +#define BIT_SENSOR_ODR_1600HZ 0x05 //(LN mode) +#define BIT_SENSOR_ODR_800HZ 0x06 //(LN mode) +#define BIT_SENSOR_ODR_400HZ 0x07 //(LP or LN mode) +#define BIT_SENSOR_ODR_200HZ 0x08 //(LP or LN mode) +#define BIT_SENSOR_ODR_100HZ 0x09 //(LP or LN mode) +#define BIT_SENSOR_ODR_50HZ 0x0A //(LP or LN mode) +#define BIT_SENSOR_ODR_25HZ 0x0B //(LP or LN mode) +#define BIT_SENSOR_ODR_12HZ 0x0C //(LP or LN mode) +#define BIT_SENSOR_ODR_6HZ 0x0D // only accel (LP mode) +#define BIT_SENSOR_ODR_3HZ 0x0E // only accel (LP mode) +#define BIT_SENSOR_ODR_1HZ 0x0F // only accel (LP mode) + +#define BIT_ACCEL_FSR_16G 0x00 +#define BIT_ACCEL_FSR_8G 0x01 +#define BIT_ACCEL_FSR_4G 0x02 +#define BIT_ACCEL_FSR_2G 0x03 + +#define BIT_GYRO_FSR_2000DPS 0X00 +#define BIT_GYRO_FSR_1000DPS 0X01 +#define BIT_GYRO_FSR_500DPS 0x02 +#define BIT_GYRO_FSR_250DPS 0x03 + +#define BIT_GYRO_UI_FS_SEL_MASK GENMASK(6, 5) +#define BIT_GYRO_ODR_MASK GENMASK(3, 0) +#define BIT_ACCEL_UI_FS_SEL_MASK GENMASK(6, 5) +#define BIT_ACCEL_ODR_MASK GENMASK(3, 0) + +/* Bank0 REG_GYRO_CONFIG1 */ +#define BIT_GYR_UI_FLT_BW_BYPASS 0x00 +#define BIT_GYR_UI_FLT_BW_180HZ 0x01 +#define BIT_GYR_UI_FLT_BW_121HZ 0x02 +#define BIT_GYR_UI_FLT_BW_73HZ 0x03 +#define BIT_GYR_UI_FLT_BW_53HZ 0x04 +#define BIT_GYR_UI_FLT_BW_34HZ 0x05 +#define BIT_GYR_UI_FLT_BW_25HZ 0x06 +#define BIT_GYR_UI_FLT_BW_16HZ 0x07 +#define BIT_GYR_UI_AVG_IND_2X 0x00 +#define BIT_GYR_UI_AVG_IND_4X 0x10 +#define BIT_GYR_UI_AVG_IND_8X 0x20 +#define BIT_GYR_UI_AVG_IND_16X 0x30 +#define BIT_GYR_UI_AVG_IND_32X 0x40 +#define BIT_GYR_UI_AVG_IND_64X 0x50 + +/* Bank0 REG_ACCEL_CONFIG1 */ +#define BIT_ACC_FILT_BW_IND_BYPASS 0x00 +#define BIT_ACC_FILT_BW_IND_180HZ 0x01 +#define BIT_ACC_FILT_BW_IND_121HZ 0x02 +#define BIT_ACC_FILT_BW_IND_73HZ 0x03 +#define BIT_ACC_FILT_BW_IND_53HZ 0x04 +#define BIT_ACC_FILT_BW_IND_34HZ 0x05 +#define BIT_ACC_FILT_BW_IND_25HZ 0x06 +#define BIT_ACC_FILT_BW_IND_16HZ 0x07 +#define BIT_ACC_UI_AVG_IND_2X 0x00 +#define BIT_ACC_UI_AVG_IND_4X 0x10 +#define BIT_ACC_UI_AVG_IND_8X 0x20 +#define BIT_ACC_UI_AVG_IND_16X 0x30 +#define BIT_ACC_UI_AVG_IND_32X 0x40 +#define BIT_ACC_UI_AVG_IND_64X 0x50 + +/* Bank0 REG_INT_CONFIG_REG */ +#define SHIFT_INT1_MODE 0x02 +#define SHIFT_INT1_DRIVE_CIRCUIT 0x01 +#define SHIFT_INT1_POLARITY 0x00 +#define BIT_ONLY_INT1_ACTIVE_HIGH \ + ((1 << SHIFT_INT1_POLARITY) | \ + (1 << SHIFT_INT1_DRIVE_CIRCUIT) | \ + (0 << SHIFT_INT1_MODE)) +#define BIT_ONLY_INT1_ACTIVE_LOW \ + ((0 << SHIFT_INT1_POLARITY) | \ + (1 << SHIFT_INT1_DRIVE_CIRCUIT) | \ + (0 << SHIFT_INT1_MODE)) + +/* Bank0 REG_PWR_MGMT_0 */ +#define BIT_PWR_MGMTO_ACCEL_LP_CLK_SEL BIT(7) +#define BIT_PWR_MGMT0_IDLE BIT(4) +#define BIT_PWR_MGMT0_GYRO(_mode) \ + FIELD_PREP(GENMASK(3, 2), (_mode)) +#define BIT_PWR_MGMT0_ACCEL(_mode) \ + FIELD_PREP(GENMASK(1, 0), (_mode)) + +#define BIT_ACCEL_MODE_OFF 0x00 +#define BIT_ACCEL_MODE_LPM 0x02 +#define BIT_ACCEL_MODE_LNM 0x03 +#define BIT_ACCEL_MODE_MASK 0x03 + +#define BIT_GYRO_MODE_OFF 0x00 +#define BIT_GYRO_MODE_STBY 0x04 +#define BIT_GYRO_MODE_LPM 0x08 +#define BIT_GYRO_MODE_LNM 0x0c +#define BIT_GYRO_MODE_MASK 0x0c + +#define BIT_IDLE 0x10 +#define BIT_ACCEL_LP_CLK_SEL 0x80 + +/* Bank0 REG_SIGNAL_PATH_RESET */ +#define BIT_FIFO_FLUSH BIT(2) +#define BIT_SOFT_RESET_CHIP_CONFIG BIT(4) + +/* Bank0 REG_INTF_CONFIG0 */ +#define BIT_FIFO_COUNT_REC_FIFO_COUNT_REC BIT(6) +#define BIT_FIFO_COUNT_REC_FIFO_COUNT_ENDIAN BIT(5) +#define BIT_FIFO_COUNT_REC_SENSOR_DATA_ENDIAN BIT(4) +#define BIT_FIFO_COUNT_REC_UI_SIFS_CFG_MASK GENMASK(1, 0) +#define BIT_FIFO_COUNT_REC_UI_SIFS_CFG_SPI_DIS \ + FIELD_PREP(BIT_FIFO_COUNT_REC_UI_SIFS_CFG_MASK, 2) +#define BIT_FIFO_COUNT_REC_UI_SIFS_CFG_I2C_DIS \ + FIELD_PREP(BIT_FIFO_COUNT_REC_UI_SIFS_CFG_MASK, 3) + +/* Bank0 REG_INTF_CONFIG1 */ +#define BIT_CLK_SEL_RC 0x00 +#define BIT_CLK_SEL_PLL 0x01 +#define BIT_CLK_SEL_DIS 0x03 +#define BIT_I3C_DDR_EN 0x04 +#define BIT_I3C_SDR_EN 0x08 +#define BIT_GYRO_AFSR_MODE_LFS 0x00 +#define BIT_GYRO_AFSR_MODE_HFS 0x20 +#define BIT_GYRO_AFSR_MODE_DYN 0x40 + +/* Bank0 REG_FIFO_CONFIG1 */ +#define BIT_FIFO_MODE_NO_BYPASS 0x00 +#define BIT_FIFO_MODE_BYPASS 0x01 +#define BIT_FIFO_MODE_STREAM 0x00 +#define BIT_FIFO_MODE_STOPFULL 0x02 + +/* Bank0 REG_FIFO_CONFIG2 / REG_FIFO_CONFIG3 */ +#define BIT_FIFO_WM5 0x10 +#define INT_FIFO_WM5_NUM 16 + +/* Bank 0 REG_INT_SOURCE0 */ +#define BIT_INT_MODE_OFF 0x00 +#define BIT_INT_AGC_RDY_INT1_EN 0x01 +#define BIT_INT_FIFO_FULL_INT1_EN 0x02 +#define BIT_INT_FIFO_THS_INT1_EN 0x04 +#define BIT_INT_DRDY_INT_EN 0x08 +#define BIT_INT_RESET_DONE_INT1_EN 0x10 +#define BIT_INT_PLL_RDY_INT1_EN 0x20 +#define BIT_INT_FSYNC_INT1_EN 0x40 +#define BIT_INT_ST_DONE_INT1_EN 0x80 + +/* Bank 0 REG_INT_SOURCE1 */ +#define BIT_INT_WOM_X_INT1_EN 0x01 +#define BIT_INT_WOM_Y_INT1_EN 0x02 +#define BIT_INT_WOM_Z_INT1_EN 0x04 +#define BIT_INT_WOM_XYZ_INT1_EN (BIT_INT_WOM_X_INT1_EN | \ + BIT_INT_WOM_Y_INT1_EN | BIT_INT_WOM_Z_INT1_EN) +#define BIT_INT_SMD_INT1_EN 0x08 +#define BIT_INT_I3C_PROTCL_ERR_INT1_EN 0x40 + +/* Bank0 REG_INT_STATUS_DRDY */ +#define BIT_INT_STATUS_DRDY 0x01 + +/* Bank0 REG_INT_STATUS */ +#define BIT_INT_STATUS_AGC_RDY 0x01 +#define BIT_INT_STATUS_FIFO_FULL 0x02 +#define BIT_INT_STATUS_FIFO_THS 0x04 +#define BIT_INT_STATUS_RESET_DONE 0x10 +#define BIT_INT_STATUS_PLL_RDY 0x20 +#define BIT_INT_STATUS_FSYNC 0x40 +#define BIT_INT_STATUS_ST_DONE 0x80 + +/* Bank0 REG_INT_STATUS2 */ +#define BIT_INT_STATUS_WOM_Z 0x01 +#define BIT_INT_STATUS_WOM_Y 0x02 +#define BIT_INT_STATUS_WOM_X 0x04 +#define BIT_INT_STATUS_WOM_XYZ (BIT_INT_STATUS_WOM_X | \ + BIT_INT_STATUS_WOM_Y | BIT_INT_STATUS_WOM_Z) +#define BIT_INT_STATUS_SMD 0x08 + +/* Bank 0 REG_INT_STATUS3 */ +#define BIT_INT_STATUS_LOWG_DET 0x02 +#define BIT_INT_STATUS_FF_DET 0x04 +#define BIT_INT_STATUS_TILT_DET 0x08 +#define BIT_INT_STATUS_STEP_CNT_OVFL 0x10 +#define BIT_INT_STATUS_STEP_DET 0x20 + +/* Bank0 REG_WOM_CONFIG */ +#define BIT_WOM_EN_OFF 0x00 +#define BIT_WOM_EN_ON 0x01 +#define BIT_WOM_MODE_INITIAL 0x00 +#define BIT_WOM_MODE_PREV 0x02 +#define BIT_WOM_INT_MODE_OR 0x00 +#define BIT_WOM_INT_MODE_AND 0x04 +#define BIT_WOM_INT_DUR_LEGACY 0x00 +#define BIT_WOM_INT_DUR_2ND 0x08 +#define BIT_WOM_INT_DUR_3RD 0x10 +#define BIT_WOM_INT_DUR_4TH 0x18 + +/* Bank0 REG_APEX_CONFIG0 */ +#define BIT_DMP_SRAM_RESET_APEX 0x01 +#define BIT_DMP_INIT_EN 0x04 +#define BIT_DMP_POWER_SAVE_EN 0x08 + +/* Bank0 REG_APEX_CONFIG1 */ +#define BIT_DMP_ODR_25HZ 0x00 +#define BIT_DMP_ODR_50HZ 0x02 +#define BIT_DMP_ODR_100HZ 0x03 +#define BIT_DMP_PEDO_EN 0x08 +#define BIT_DMP_TILT_EN 0x10 +#define BIT_DMP_FF_EN 0x20 +#define BIT_DMP_SMD_EN 0x40 + +/* Bank0 REG_WHO_AM_I */ +#define BIT_I_AM_ICM42670 0x67 + +/* REG_OTP_CONFIG_MREG_TOP1 */ +#define BIT_OTP_COPY_NORMAL 0x04 +#define BIT_OTP_COPY_ST_DATA 0x0C +#define OTP_COPY_MODE_MASK 0x0C + +/* REG_INT_SOURCE6_MREG_TOP1 */ +#define BIT_INT_TLT_DET_INT1_EN 0x08 +#define BIT_INT_STEP_CNT_OVFL_INT1_EN 0x10 +#define BIT_INT_STEP_DET_INT1_EN 0x20 +#define BIT_INT_LOWG_INT1_EN 0x40 +#define BIT_INT_FF_INT1_EN 0x80 + +/* REG_TMST_CONFIG1_MREG_TOP1 */ +#define BIT_TMST_EN 0x01 +#define BIT_TMST_FSYNC_EN 0x02 +#define BIT_TMST_DELTA_EN 0x04 +#define BIT_TMST_RESOL 0x08 +#define BIT_TMST_ON_SREG_EN 0x10 +#define BIT_ODR_EN_WITHOUT_SENSOR 0x40 + +/* REG_FIFO_CONFIG5_MREG_TOP1 */ +#define BIT_FIFO_ACCEL_EN 0x01 +#define BIT_FIFO_GYRO_EN 0x02 +#define BIT_FIFO_TMST_FSYNC_EN 0x04 +#define BIT_FIFO_HIRES_EN 0x08 +#define BIT_RESUME_PARTIAL_RD 0x10 +#define BIT_WM_GT_TH 0x20 + +/* REG_SELFTEST_MREG_TOP1 */ +#define BIT_EN_AX_ST 0x01 +#define BIT_EN_AY_ST 0x02 +#define BIT_EN_AZ_ST 0x04 +#define BIT_EN_GX_ST 0x08 +#define BIT_EN_GY_ST 0x10 +#define BIT_EN_GZ_ST 0x20 +#define BIT_ACCEL_ST_EN 0x40 +#define BIT_GYRO_ST_EN 0x80 + +/* REG_ST_CONFIG_MREG_TOP1 */ +#define BIT_PD_ACCEL_CP45_ST_REG 0x80 +#define SHIFT_GYRO_ST_LIM 0 +#define SHIFT_ACCEL_ST_LIM 3 +#define SHIFT_ST_NUM_SAMPLE 6 + +/* REG_ST_STATUS1_MREG_TOP1 */ +#define BIT_DMP_AX_ST_PASS 0x02 +#define BIT_DMP_AY_ST_PASS 0x04 +#define BIT_DMP_AZ_ST_PASS 0x08 +#define BIT_DMP_ACCEL_ST_DONE 0x10 +#define BIT_DMP_ACCEL_ST_PASS 0x20 + +/* REG_ST_STATUS2_MREG_TOP1 */ +#define BIT_DMP_GX_ST_PASS 0x02 +#define BIT_DMP_GY_ST_PASS 0x04 +#define BIT_DMP_GZ_ST_PASS 0x08 +#define BIT_DMP_GYRO_ST_DONE 0x10 +#define BIT_DMP_GYRO_ST_PASS 0x20 +#define BIT_DMP_ST_INCOMPLETE 0x40 + +/* REG_OTP_CTRL7_MREG_OTP */ +#define BIT_OTP_RELOAD 0x08 +#define BIT_OTP_PWR_DOWN 0x02 + +/** FIFO CONTENT DEFINITION */ +#define HEADER_SIZE 1 +#define ACCEL_DATA_SIZE 6 +#define GYRO_DATA_SIZE 6 +#define TEMP_DATA_SIZE 1 +#define TS_FSYNC_SIZE 2 + +/* M-reg access wait tile */ +#define ICM42670_MCLK_WAIT_US 20 +#define ICM42670_BLK_SEL_WAIT_US 10 +#define ICM42670_MADDR_WAIT_US 10 +#define ICM42670_M_RW_WAIT_US 10 + + +/* Allowed timestamp period jitter in percent */ +#define ICM42670_TS_PERIOD_JITTER 4 + +enum ICM406xx_fio_format { + FIFO_20_BYTE, + FIFO_ACCEL_ONLY, + FIFO_GYRO_ONLY, + FIFO_16_BYTE, +}; + +enum inv_icm42670_sensor_mode { + INV_ICM42670_SENSOR_MODE_OFF, + INV_ICM42670_SENSOR_MODE_STANDBY, + INV_ICM42670_SENSOR_MODE_LOW_POWER, + INV_ICM42670_SENSOR_MODE_LOW_NOISE, + INV_ICM42670_SENSOR_MODE_NB, +}; + +#define FIFO_ACCEL_EN 0x40 +#define FIFO_GYRO_EN 0x20 +#define FIFO_TS_MASK 0x0C +#define FIFO_FSYNC_BITS 0x0C +#define HAVANA_MAX_PACKET_SIZE 20 +#define ICM42670_FIFO_COUNT_LIMIT 60 +#define ICM42670_DATA_BUFF_SIZE 960 + +// ODR +enum icm42670_odr_index { + ICM42670_ODR_RESERVED0 = 0, + ICM42670_ODR_RESERVED1, + ICM42670_ODR_RESERVED2, + ICM42670_ODR_8KHZ, + ICM42670_ODR_4KHZ, + ICM42670_ODR_2KHZ, + ICM42670_ODR_1KHZ, + ICM42670_ODR_200HZ, + ICM42670_ODR_100HZ, + ICM42670_ODR_50HZ, + ICM42670_ODR_25HZ, + ICM42670_NUM_ODRS, /* must be last */ +}; + +struct icm42670_chip_config { + unsigned int fsr:2; + unsigned int lpf:3; + unsigned int accl_fs:2; + int gyro_odr:10; + int accel_odr:10; + unsigned int accl_fifo_enable:1; + unsigned int gyro_fifo_enable:1; + unsigned int temp_fifo_enable:1; + unsigned int time_fifo_enable:1; + u8 divider; + u8 user_ctrl; +}; + +struct icm42670_data { + struct mutex lock; + struct regmap *regmap; + struct iio_trigger *trig; + struct device_node *node; + int int1_gpio; + struct regulator *vdd_supply; + struct regulator *vddio_supply; + u16 accel_frequency; + u16 gyro_frequency; + u16 accel_frequency_buff; + u16 gyro_frequency_buff; + int irq; + u8 irq_mask; + int chip_type; // not used + unsigned int powerup_count; + struct icm42670_chip_config chip_config; + int skip_samples; + s64 it_timestamp; // Timestamp of when the data was read + s64 data_timestamp; // Timestamp of when the data was generated + s64 standard_period; // Standard interrupt period in nanoseconds + s64 interrupt_period; // Actual interrupt period in nanoseconds + s64 period_min; // Minimum interrupt period deviation in nanoseconds + s64 period_max; // Maximum interrupt period deviation in nanoseconds + int period_divider; + int interrupt_regval; + u8 data_buff[ICM42670_DATA_BUFF_SIZE]; +}; + +/* scan indexes follow DATA register order */ +enum icm42670_scan_axis { + ICM42670_SCAN_ACCEL_X = 0, + ICM42670_SCAN_ACCEL_Y, + ICM42670_SCAN_ACCEL_Z, + ICM42670_SCAN_GYRO_X, + ICM42670_SCAN_GYRO_Y, + ICM42670_SCAN_GYRO_Z, + ICM42670_SCAN_TEMP, + ICM42670_SCAN_TIMESTAMP, +}; + +enum icm42670_sensor_type { + ICM42670_ACCEL = 0, + ICM42670_GYRO, + ICM42670_TEMP, + ICM42670_TIMESTAMP, + ICM42670_NUM_SENSORS /* must be last */ +}; + +#define IIO_TRIGGER 1 +#define ICM42670_RESET_FLAG 1 +#define ICM42670_DEBUG_FLAG 0 + +// fifo +#define ICM42670_OUTPUT_DATA_SIZE 24 // align 8, last 8 for timestamp +#define ICM42670_OUTPUT_DATA_SIZE_PULS_ONE 25 +#define ICM42670_FIFO_DATUM 16 +#define ICM42670_BYTES_PER_3AXIS_SENSOR 6 +#define ICM42670_FIFO_COUNT_BYTE 2 +#define ICM42670_BYTE_FIFO_TEMP 1 +#define ICM42670_FIFO_SIZE 1024 + +typedef int (*icm42670_bus_setup)(struct icm42670_data *); + +extern const struct regmap_config icm42670_regmap_config; +extern const struct dev_pm_ops icm42670_pm_ops; + +irqreturn_t icm42670_read_fifo(int irq, void *p); +int icm42670_reset_fifo(struct iio_dev *indio_dev); +int icm42670_core_probe(struct regmap *regmap, int irq, const char *name, + int chip_type, icm42670_bus_setup bus_setup); +void icm42670_core_remove(struct device *dev); +int icm42670_probe_trigger(struct iio_dev *indio_dev, int irq_type); +int icm42670_set_enable(struct iio_dev *indio_dev, bool enable); +int icm42670_mreg_single_write(struct icm42670_data *st, int addr, u32 data); +int icm42670_set_mode(struct icm42670_data *data, + enum icm42670_sensor_type t, + bool mode); +int icm42670_mreg_read(struct icm42670_data *st, int addr, int len, u32 *data); + +#endif diff --git a/drivers/iio/imu/inv_icm42670/inv_icm42670_core.c b/drivers/iio/imu/inv_icm42670/inv_icm42670_core.c new file mode 100644 index 000000000000..901ca0d66a6d --- /dev/null +++ b/drivers/iio/imu/inv_icm42670/inv_icm42670_core.c @@ -0,0 +1,1122 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2024 Rockchip Electronics Co., Ltd. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "inv_icm42670.h" + +static int icm42670_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask); + +static int icm42670_write_raw_get_fmt(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + long mask); + +static int icm42670_set_scale(struct icm42670_data *data, + enum icm42670_sensor_type t, + int scale, int uscale); + +static int icm42670_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask); + +static int icm42670_set_odr(struct icm42670_data *data, + enum icm42670_sensor_type t, + int odr); + +#define ICM42670_CHANNEL(_type, _axis, _index) { \ + .type = _type, \ + .modified = 1, \ + .channel2 = _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), \ + .scan_index = _index, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 16, \ + .storagebits = 16, \ + .endianness = IIO_BE, \ + }, \ +} + +#define ICM42670_TEMP_CHANNEL(_type, _index) { \ + .type = _type, \ + .channel = -1, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .scan_index = _index, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 8, \ + .storagebits = 8, \ + .endianness = IIO_BE, \ + }, \ +} + +static const struct iio_chan_spec icm42670_channels[] = { + ICM42670_CHANNEL(IIO_ACCEL, IIO_MOD_X, ICM42670_SCAN_ACCEL_X), + ICM42670_CHANNEL(IIO_ACCEL, IIO_MOD_Y, ICM42670_SCAN_ACCEL_Y), + ICM42670_CHANNEL(IIO_ACCEL, IIO_MOD_Z, ICM42670_SCAN_ACCEL_Z), + ICM42670_CHANNEL(IIO_ANGL_VEL, IIO_MOD_X, ICM42670_SCAN_GYRO_X), + ICM42670_CHANNEL(IIO_ANGL_VEL, IIO_MOD_Y, ICM42670_SCAN_GYRO_Y), + ICM42670_CHANNEL(IIO_ANGL_VEL, IIO_MOD_Z, ICM42670_SCAN_GYRO_Z), + ICM42670_TEMP_CHANNEL(IIO_TEMP, ICM42670_SCAN_TEMP), + IIO_CHAN_SOFT_TIMESTAMP(ICM42670_SCAN_TIMESTAMP), +}; + +static const unsigned long icm42670_scan_masks[] = { + /* 3-axis accel + temp */ + BIT(ICM42670_SCAN_ACCEL_X) + | BIT(ICM42670_SCAN_ACCEL_Y) + | BIT(ICM42670_SCAN_ACCEL_Z) + | BIT(ICM42670_SCAN_TEMP), + /* 3-axis gyro + temp */ + BIT(ICM42670_SCAN_GYRO_X) + | BIT(ICM42670_SCAN_GYRO_Y) + | BIT(ICM42670_SCAN_GYRO_Z) + | BIT(ICM42670_SCAN_TEMP), + /* 6-axis accel + gyro + temp */ + BIT(ICM42670_SCAN_ACCEL_X) + | BIT(ICM42670_SCAN_ACCEL_Y) + | BIT(ICM42670_SCAN_ACCEL_Z) + | BIT(ICM42670_SCAN_GYRO_X) + | BIT(ICM42670_SCAN_GYRO_Y) + | BIT(ICM42670_SCAN_GYRO_Z) + | BIT(ICM42670_SCAN_TEMP), + 0, +}; + +struct icm42670_regs { + u8 data; + u8 config; + u8 config_odr_mask; + u8 config_fsr_mask; +}; + +static struct icm42670_regs icm42670_regs[] = { + [ICM42670_ACCEL] = { + .data = REG_ACCEL_DATA_X0_UI, + .config = REG_ACCEL_CONFIG0, + .config_odr_mask = BIT_ACCEL_ODR_MASK, + .config_fsr_mask = BIT_ACCEL_UI_FS_SEL_MASK, + }, + [ICM42670_GYRO] = { + .data = REG_GYRO_DATA_X0_UI, + .config = REG_GYRO_CONFIG0, + .config_odr_mask = BIT_GYRO_ODR_MASK, + .config_fsr_mask = BIT_GYRO_UI_FS_SEL_MASK, + }, + [ICM42670_TEMP] = { + .data = REG_TEMP_DATA0_UI, + .config = REG_TEMP_CONFIG0, + .config_odr_mask = 0, + .config_fsr_mask = 0, + }, +}; + +static IIO_CONST_ATTR(in_accel_sampling_frequency_available, + "1 3 6 12 25 50 100 200 400 800"); +static IIO_CONST_ATTR(in_anglvel_sampling_frequency_available, + "12 25 50 100 200 400 800"); +static IIO_CONST_ATTR(in_accel_scale_available, + "0.000598 0.001196 0.002393 0.004785"); +static IIO_CONST_ATTR(in_anglvel_scale_available, + "0.000133231 0.000266462 0.000532113 0.001064225"); + +static struct attribute *icm42670_attrs[] = { + &iio_const_attr_in_accel_sampling_frequency_available.dev_attr.attr, + &iio_const_attr_in_anglvel_sampling_frequency_available.dev_attr.attr, + &iio_const_attr_in_accel_scale_available.dev_attr.attr, + &iio_const_attr_in_anglvel_scale_available.dev_attr.attr, + NULL, +}; + +static const struct attribute_group icm42670_attrs_group = { + .attrs = icm42670_attrs, +}; + +static const struct iio_info icm42670_info = { + .read_raw = icm42670_read_raw, + .write_raw = icm42670_write_raw, + .write_raw_get_fmt = &icm42670_write_raw_get_fmt, + .attrs = &icm42670_attrs_group, +}; + +struct icm42670_odr { + u8 bits; + int odr; + int divider; //us +}; + +struct icm42670_odr_item { + const struct icm42670_odr *tbl; + int num; +}; + +static const struct icm42670_odr icm42670_accel_odr[] = { + {BIT_SENSOR_ODR_1600HZ, 1600, 1600}, + {BIT_SENSOR_ODR_800HZ, 800, -1250}, + {BIT_SENSOR_ODR_400HZ, 400, -2500}, + {BIT_SENSOR_ODR_200HZ, 200, -5000}, + {BIT_SENSOR_ODR_100HZ, 100, -10000}, + {BIT_SENSOR_ODR_50HZ, 50, -20000}, + {BIT_SENSOR_ODR_25HZ, 25, -40000}, + {BIT_SENSOR_ODR_12HZ, 12, -80000}, + {BIT_SENSOR_ODR_6HZ, 6, -160000}, + {BIT_SENSOR_ODR_3HZ, 3, -320000}, + {BIT_SENSOR_ODR_1HZ, 1, -640000}, +}; + +static const struct icm42670_odr icm42670_gyro_odr[] = { + {BIT_SENSOR_ODR_1600HZ, 1600, 1600}, + {BIT_SENSOR_ODR_800HZ, 800, -1250}, + {BIT_SENSOR_ODR_400HZ, 400, -2500}, + {BIT_SENSOR_ODR_200HZ, 200, -5000}, + {BIT_SENSOR_ODR_100HZ, 100, -10000}, + {BIT_SENSOR_ODR_50HZ, 50, -20000}, + {BIT_SENSOR_ODR_25HZ, 25, -40000}, + {BIT_SENSOR_ODR_12HZ, 12, -80000}, +}; + +static const struct icm42670_odr_item icm42670_odr_table[] = { + [ICM42670_ACCEL] = { + .tbl = icm42670_accel_odr, + .num = ARRAY_SIZE(icm42670_accel_odr), + }, + [ICM42670_GYRO] = { + .tbl = icm42670_gyro_odr, + .num = ARRAY_SIZE(icm42670_gyro_odr), + }, +}; + +struct icm42670_scale { + u8 bits; + int scale; + int uscale; +}; + +struct icm42670_scale_item { + const struct icm42670_scale *tbl; + int num; + int format; +}; + +/* + * this is the accel scale translated from dynamic range plus/minus + * {2, 4, 8, 16} to m/s^2 + * Formula: Range / Sampling Accuracy * Gravity Acceleration + * For ±2g full scale, 598 = 4(-2g, -1g, 1g, 2g) / 2^16 * 9.8(1g) * 1000000 + * For ±4g full scale, 1196 = 8 / 2^16 * 9.8 * 1000000 + */ +static const struct icm42670_scale icm42670_accel_scale[] = { + {BIT_ACCEL_FSR_2G, 0, 598}, + {BIT_ACCEL_FSR_4G, 0, 1196}, + {BIT_ACCEL_FSR_8G, 0, 2393}, + {BIT_ACCEL_FSR_16G, 0, 4785}, +}; + +/* + * this is the gyro scale translated from dynamic range plus/minus + * {250, 500, 1000, 2000} to rad/s + * Formula: Range / sampling accuracy * Radians + * For ±2000DPS full scale, 1064225 = 4000 / 2^16 * (π/180) * 1000000000 + */ +static const struct icm42670_scale icm42670_gyro_scale[] = { + { BIT_GYRO_FSR_250DPS, 0, 133231}, + { BIT_GYRO_FSR_500DPS, 0, 266462}, + { BIT_GYRO_FSR_1000DPS, 0, 532113}, + { BIT_GYRO_FSR_2000DPS, 0, 1064225}, +}; + +static const struct icm42670_scale_item icm42670_scale_table[] = { + [ICM42670_ACCEL] = { + .tbl = icm42670_accel_scale, + .num = ARRAY_SIZE(icm42670_accel_scale), + .format = IIO_VAL_INT_PLUS_MICRO, + }, + [ICM42670_GYRO] = { + .tbl = icm42670_gyro_scale, + .num = ARRAY_SIZE(icm42670_gyro_scale), + .format = IIO_VAL_INT_PLUS_NANO, + }, +}; + +const struct regmap_config icm42670_regmap_config = { + .reg_bits = 8, + .val_bits = 8, +}; +EXPORT_SYMBOL(icm42670_regmap_config); + +static enum icm42670_sensor_type icm42670_to_sensor(enum iio_chan_type iio_type) +{ + switch (iio_type) { + case IIO_ACCEL: + return ICM42670_ACCEL; + case IIO_ANGL_VEL: + return ICM42670_GYRO; + case IIO_TEMP: + return ICM42670_TEMP; + default: + return -EINVAL; + } +} + +static int icm42670_gyro_on(struct icm42670_data *data) +{ + int ret; + unsigned int cmd; + + // Enable Gyro + ret = regmap_read(data->regmap, REG_PWR_MGMT_0, &cmd); + if (ret < 0) + return ret; + + cmd |= BIT_PWR_MGMT0_GYRO(INV_ICM42670_SENSOR_MODE_LOW_NOISE); // Gyro on in LNM + usleep_range(50, 51); + ret = regmap_write(data->regmap, REG_PWR_MGMT_0, cmd); + if (ret < 0) + return ret; + usleep_range(200, 201); + + return ret; +} + +static int icm42670_gyro_off(struct icm42670_data *data) +{ + int ret; + unsigned int cmd; + + ret = regmap_read(data->regmap, REG_PWR_MGMT_0, &cmd); + if (ret < 0) + return ret; + + cmd &= (~(BIT_PWR_MGMT0_GYRO(INV_ICM42670_SENSOR_MODE_LOW_NOISE))); // Gyro off + msleep(80); + ret = regmap_write(data->regmap, REG_PWR_MGMT_0, cmd); + if (ret < 0) + return ret; + msleep(200); + return ret; +} + +static int icm42670_accel_on(struct icm42670_data *data) +{ + int ret; + unsigned int cmd; + + ret = regmap_read(data->regmap, REG_PWR_MGMT_0, &cmd); + if (ret < 0) + return ret; + cmd |= (BIT_PWR_MGMT0_ACCEL(INV_ICM42670_SENSOR_MODE_LOW_NOISE)); // Accel on in LNM + ret = regmap_write(data->regmap, REG_PWR_MGMT_0, cmd); + if (ret < 0) + return ret; + usleep_range(200, 201); + + return ret; +} + +static int icm42670_accel_off(struct icm42670_data *data) +{ + int ret; + unsigned int cmd; + + ret = regmap_read(data->regmap, REG_PWR_MGMT_0, &cmd); + if (ret < 0) + return ret; + cmd &= (~(BIT_PWR_MGMT0_ACCEL(INV_ICM42670_SENSOR_MODE_LOW_NOISE))); // Accel on in LNM + usleep_range(50, 51); + ret = regmap_write(data->regmap, REG_PWR_MGMT_0, cmd); + if (ret < 0) + return ret; + usleep_range(200, 201); + return ret; +} + +int icm42670_set_mode(struct icm42670_data *data, + enum icm42670_sensor_type t, + bool mode) +{ + int ret; + + if (t == ICM42670_GYRO) { + if (mode) + ret = icm42670_gyro_on(data); + else + ret = icm42670_gyro_off(data); + } else if (t == ICM42670_ACCEL) { + if (mode) + ret = icm42670_accel_on(data); + else + ret = icm42670_accel_off(data); + } else { + return -EINVAL; + } + + return ret; +} + +/** + * icm42670_mreg_read() - Multiple byte read from MREG area. + * @st: struct icm42670_data. + * @addr: MREG register start address including bank in upper byte. + * @len: length to read in byte. + * @data: pointer to store read data. + * + * Return: 0 when successful. + */ +int icm42670_mreg_read(struct icm42670_data *st, int addr, int len, u32 *data) +{ + int ret; + u32 reg_pwr_mgmt_0; + + ret = regmap_read(st->regmap, REG_PWR_MGMT_0, ®_pwr_mgmt_0); + if (ret) + return ret; + + //TODO: set idle + + ret = regmap_write(st->regmap, REG_BLK_SEL_R, (addr >> 8) & 0xff); + usleep_range(ICM42670_BLK_SEL_WAIT_US, + ICM42670_BLK_SEL_WAIT_US + 1); + if (ret) + goto restore_bank; + + ret = regmap_write(st->regmap, REG_MADDR_R, addr & 0xff); + usleep_range(ICM42670_MADDR_WAIT_US, + ICM42670_MADDR_WAIT_US + 1); + if (ret) + goto restore_bank; + + ret = regmap_read(st->regmap, REG_M_R, data); + usleep_range(ICM42670_M_RW_WAIT_US, + ICM42670_M_RW_WAIT_US + 1); + if (ret) + goto restore_bank; + +restore_bank: + ret |= regmap_write(st->regmap, REG_BLK_SEL_R, 0); + usleep_range(ICM42670_BLK_SEL_WAIT_US, + ICM42670_BLK_SEL_WAIT_US + 1); + + ret |= regmap_write(st->regmap, REG_PWR_MGMT_0, reg_pwr_mgmt_0); + + return ret; +} + +/** + * icm42670_mreg_single_write() - Single byte write to MREG area. + * @st: struct icm42670_data. + * @addr: MREG register address including bank in upper byte. + * @data: data to write. + * + * Return: 0 when successful. + */ +int icm42670_mreg_single_write(struct icm42670_data *st, int addr, u32 data) +{ + int ret; + u32 reg_pwr_mgmt_0; + + ret = regmap_read(st->regmap, REG_PWR_MGMT_0, ®_pwr_mgmt_0); + if (ret) + return ret; + + //TODO: set idle + + ret = regmap_write(st->regmap, REG_BLK_SEL_W, (addr >> 8) & 0xff); + usleep_range(ICM42670_BLK_SEL_WAIT_US, + ICM42670_BLK_SEL_WAIT_US + 1); + if (ret) + goto restore_bank; + + ret = regmap_write(st->regmap, REG_MADDR_W, addr & 0xff); + usleep_range(ICM42670_MADDR_WAIT_US, + ICM42670_MADDR_WAIT_US + 1); + if (ret) + goto restore_bank; + + ret = regmap_write(st->regmap, REG_M_W, data); + usleep_range(ICM42670_M_RW_WAIT_US, + ICM42670_M_RW_WAIT_US + 1); + if (ret) + goto restore_bank; + +restore_bank: + ret |= regmap_write(st->regmap, REG_BLK_SEL_W, 0); + usleep_range(ICM42670_BLK_SEL_WAIT_US, + ICM42670_BLK_SEL_WAIT_US + 1); + + ret |= regmap_write(st->regmap, REG_PWR_MGMT_0, reg_pwr_mgmt_0); + + return ret; +} + +static int icm42670_get_scale(struct icm42670_data *data, + enum icm42670_sensor_type t, + int *scale, int *uscale) +{ + int i, ret, val; + + if (t < 0 || (t >= ARRAY_SIZE(icm42670_scale_table))) + return -EINVAL; + + ret = regmap_read(data->regmap, icm42670_regs[t].config, &val); + if (ret < 0) + return ret; + + val = ((val) & (icm42670_regs[t].config_fsr_mask)) >> + __builtin_ctzl(icm42670_regs[t].config_fsr_mask); + + for (i = 0; i < icm42670_scale_table[t].num; i++) + if (icm42670_scale_table[t].tbl[i].bits == val) { + + *scale = icm42670_scale_table[t].tbl[i].scale; + *uscale = icm42670_scale_table[t].tbl[i].uscale; + + return icm42670_scale_table[t].format; + } + + return -EINVAL; +} + +static int icm42670_get_odr(struct icm42670_data *data, + enum icm42670_sensor_type t, + int *odr) +{ + int i, val, ret; + + if (t < 0 || t >= ARRAY_SIZE(icm42670_odr_table)) + return 0; + + ret = regmap_read(data->regmap, icm42670_regs[t].config, &val); + if (ret < 0) + return ret; + + val = ((val) & (icm42670_regs[t].config_odr_mask)) >> + __builtin_ctzl(icm42670_regs[t].config_odr_mask); + + for (i = 0; i < icm42670_odr_table[t].num; i++) + if (val == icm42670_odr_table[t].tbl[i].bits) + break; + + if (i >= icm42670_odr_table[t].num) + return -EINVAL; + + *odr = icm42670_odr_table[t].tbl[i].odr; + + return 0; +} + +static int icm42670_get_data(struct icm42670_data *data, + enum icm42670_sensor_type t, + int axis, int *val) +{ + u8 reg; + int ret; + __be16 sample; + + if (t == ICM42670_TEMP) + reg = icm42670_regs[t].data; + else + reg = icm42670_regs[t].data + (axis - IIO_MOD_X) * sizeof(sample); + + ret = regmap_bulk_read(data->regmap, reg, (u8 *)&sample, 2); + if (ret) + return -EINVAL; + + *val = (short)be16_to_cpup(&sample); + dev_info(regmap_get_device(data->regmap), + "icm42670get_data: ch: %d, aix: %d, reg: %x, val: %x\n", + t, axis, reg, *val); + + return ret; +} + +static int icm42670_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + int ret; + struct icm42670_data *data = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; + mutex_lock(&data->lock); + icm42670_get_data(data, icm42670_to_sensor(chan->type), chan->channel2, val); + mutex_unlock(&data->lock); + iio_device_release_direct_mode(indio_dev); + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + mutex_lock(&data->lock); + ret = icm42670_get_scale(data, icm42670_to_sensor(chan->type), val, val2); + mutex_unlock(&data->lock); + return ret; + case IIO_CHAN_INFO_SAMP_FREQ: + mutex_lock(&data->lock); + ret = icm42670_get_odr(data, icm42670_to_sensor(chan->type), val); + mutex_unlock(&data->lock); + return ret < 0 ? ret : IIO_VAL_INT; + default: + return -EINVAL; + } + + return 0; +} + +static int icm42670_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + int ret = 0; + struct icm42670_data *data = iio_priv(indio_dev); + + mutex_lock(&data->lock); + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + goto error_write_raw_unlock; + + switch (mask) { + case IIO_CHAN_INFO_SCALE: + ret = icm42670_set_scale(data, + icm42670_to_sensor(chan->type), + val, + val2); + break; + case IIO_CHAN_INFO_SAMP_FREQ: + ret = icm42670_set_odr(data, + icm42670_to_sensor(chan->type), + val); + break; + default: + ret = -EINVAL; + } + +error_write_raw_unlock: + iio_device_release_direct_mode(indio_dev); + mutex_unlock(&data->lock); + return ret; +} + +static int icm42670_write_raw_get_fmt(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + long mask) +{ + switch (mask) { + case IIO_CHAN_INFO_SCALE: + switch (chan->type) { + case IIO_ANGL_VEL: + return IIO_VAL_INT_PLUS_NANO; + default: + return IIO_VAL_INT_PLUS_MICRO; + } + default: + return IIO_VAL_INT_PLUS_MICRO; + } + + return -EINVAL; +} + +static const char *icm42670_match_acpi_device(struct device *dev) +{ + const struct acpi_device_id *id; + + id = acpi_match_device(dev->driver->acpi_match_table, dev); + if (!id) + return NULL; + + return dev_name(dev); +} + +static void icm42670_chip_uninit(struct icm42670_data *data) +{ + icm42670_set_mode(data, ICM42670_GYRO, false); + icm42670_set_mode(data, ICM42670_ACCEL, false); +} + +static void icm42670_disable_vdd_reg(void *_data) +{ + struct icm42670_data *st = _data; + const struct device *dev = regmap_get_device(st->regmap); + int ret; + + ret = regulator_disable(st->vdd_supply); + if (ret) + dev_err(dev, "failed to disable vdd error %d\n", ret); +} + +static int __icm42670_set_fsr(struct icm42670_data *data, + enum icm42670_sensor_type t, int sel) +{ + int ret; + unsigned int cmd; + + if (t == ICM42670_ACCEL) { + ret = regmap_read(data->regmap, REG_ACCEL_CONFIG0, &cmd); + if (ret < 0) + return ret; + + if (FIELD_GET(BIT_ACCEL_UI_FS_SEL_MASK, cmd) == sel) + return 0; + + ret = regmap_update_bits(data->regmap, REG_ACCEL_CONFIG0, + BIT_ACCEL_UI_FS_SEL_MASK, + FIELD_PREP(BIT_ACCEL_UI_FS_SEL_MASK, sel)); + } else if (t == ICM42670_GYRO) { + ret = regmap_read(data->regmap, REG_GYRO_CONFIG0, &cmd); + if (ret < 0) + return ret; + + if (FIELD_GET(BIT_GYRO_UI_FS_SEL_MASK, cmd) == sel) + return 0; + + ret = regmap_update_bits(data->regmap, REG_GYRO_CONFIG0, + BIT_GYRO_UI_FS_SEL_MASK, + FIELD_PREP(BIT_GYRO_UI_FS_SEL_MASK, sel)); + } else { + return -EINVAL; + } + + return ret; +} + +static int icm42670_set_scale(struct icm42670_data *data, + enum icm42670_sensor_type t, + int scale, int uscale) +{ + int i; + + if (t >= ARRAY_SIZE(icm42670_scale_table)) + return -EINVAL; + + for (i = 0; i < icm42670_scale_table[t].num; i++) + if (icm42670_scale_table[t].tbl[i].uscale == uscale && + icm42670_scale_table[t].tbl[i].scale == scale) + break; + + if (i == icm42670_scale_table[t].num) + return -EINVAL; + + dev_info(regmap_get_device(data->regmap), "set scale t: %d, bit: %x\n", + t, icm42670_scale_table[t].tbl[i].bits); + return __icm42670_set_fsr(data, t, icm42670_scale_table[t].tbl[i].bits); +} + +static int __icm42670_set_odr(struct icm42670_data *data, + enum icm42670_sensor_type t, + int sel, int divider) +{ + int ret; + unsigned int cmd; + + if (t == ICM42670_ACCEL) { + ret = regmap_read(data->regmap, REG_ACCEL_CONFIG0, &cmd); + if (ret < 0) + return ret; + + if (FIELD_GET(BIT_ACCEL_ODR_MASK, cmd) == sel) + return 0; + + cmd &= (~BIT_ACCEL_ODR_MASK); + cmd |= sel; + ret = regmap_write(data->regmap, REG_ACCEL_CONFIG0, cmd); + if (!ret) { + data->chip_config.accel_odr = sel; + /* Select the largest of multiple sampling periods */ + data->period_divider = + (data->period_divider && data->period_divider > divider) ? + data->period_divider : divider; + } + } else if (t == ICM42670_GYRO) { + ret = regmap_read(data->regmap, REG_GYRO_CONFIG0, &cmd); + if (ret < 0) + return ret; + + if (FIELD_GET(BIT_GYRO_ODR_MASK, cmd) == sel) + return 0; + + cmd &= (~BIT_GYRO_ODR_MASK); + cmd |= sel; + ret = regmap_write(data->regmap, REG_GYRO_CONFIG0, cmd); + if (!ret) { + data->chip_config.gyro_odr = sel; + /* Select the largest of multiple sampling periods */ + data->period_divider = + (data->period_divider && data->period_divider > divider) ? + data->period_divider : divider; + } + } else { + return -EINVAL; + } + + return ret; +} + +static int icm42670_set_odr(struct icm42670_data *data, + enum icm42670_sensor_type t, + int odr) +{ + int i; + + if (t == ICM42670_ACCEL) + data->accel_frequency = odr; + + if (t == ICM42670_GYRO) + data->gyro_frequency = odr; + + if (t >= ARRAY_SIZE(icm42670_odr_table)) + return -EINVAL; + + for (i = 0; i < icm42670_odr_table[t].num; i++) + if (icm42670_odr_table[t].tbl[i].odr == odr) + break; + + if (i >= icm42670_odr_table[t].num) + return -EINVAL; + + dev_info(regmap_get_device(data->regmap), "set odr t: %d, bit: %x\n", t, + icm42670_odr_table[t].tbl[i].bits); + + return __icm42670_set_odr(data, t, icm42670_odr_table[t].tbl[i].bits, + icm42670_odr_table[t].tbl[i].divider); +} + +static int icm42670_chip_init(struct icm42670_data *data, icm42670_bus_setup bus_setup) +{ + int ret; + unsigned int regval; + struct device *dev = regmap_get_device(data->regmap); + + // who am i + ret = regmap_read(data->regmap, REG_WHO_AM_I, ®val); + if (ret) + return ret; + + dev_info(dev, "i am: %x, icm42670: %0x\n", regval, BIT_I_AM_ICM42670); + + if (regval != BIT_I_AM_ICM42670) + return -EINVAL; + + // reset + ret = regmap_write(data->regmap, REG_SIGNAL_PATH_RESET, BIT_SOFT_RESET_CHIP_CONFIG); + if (ret < 0) + return ret; + + usleep_range(1000, 2000); + + /* check reset done bit in interrupt status */ + ret = regmap_read(data->regmap, REG_INT_STATUS, ®val); + if (ret) + return ret; + + if (!(regval & BIT_INT_STATUS_RESET_DONE)) { + dev_err(dev, "reset done status bit missing (%0x)\n", regval); + return -ENODEV; + } + // Configure the INT1 GPIO as input + ret = gpio_direction_input(data->int1_gpio); + if (ret < 0) + dev_err(dev, "gpio_direction_input failed!\r\n"); + + /* set chip bus configuration */ + ret = bus_setup(data); + if (ret) { + dev_err(dev, "bus_setup failed!\r\n"); + return ret; + } + + /* FIFO count is reported in records (1 record = 16 bytes for gyro+accel+tempsensor data) */ + ret = regmap_update_bits(data->regmap, REG_INTF_CONFIG0, + BIT_FIFO_COUNT_REC_FIFO_COUNT_REC, + BIT_FIFO_COUNT_REC_FIFO_COUNT_REC); + if (ret) + return ret; + + /* FIFO data in big-endian (default) */ + ret = regmap_update_bits(data->regmap, REG_INTF_CONFIG0, + BIT_FIFO_COUNT_REC_FIFO_COUNT_ENDIAN, + BIT_FIFO_COUNT_REC_FIFO_COUNT_ENDIAN); + if (ret) + return ret; + + /* sensor data in big-endian (default) */ + ret = regmap_update_bits(data->regmap, REG_INTF_CONFIG0, + BIT_FIFO_COUNT_REC_SENSOR_DATA_ENDIAN, + BIT_FIFO_COUNT_REC_SENSOR_DATA_ENDIAN); + if (ret) + return ret; + + ret = icm42670_set_mode(data, ICM42670_ACCEL, true); + if (ret < 0) { + dev_err(dev, "icm42670_set_mode ICM42670_ACCEL failed!\r\n"); + return ret; + } + + ret = icm42670_set_mode(data, ICM42670_GYRO, true); + if (ret < 0) { + dev_err(dev, "icm42670_set_mode ICM42670_GYRO failed!\r\n"); + return ret; + } + + // init gyro and accel para + ret = icm42670_set_odr(data, ICM42670_ACCEL, icm42670_accel_odr[0].odr); + if (ret < 0) { + dev_err(dev, "icm42670_set_odr ICM42670_ACCEL failed!\r\n"); + return ret; + } + + ret = icm42670_set_odr(data, ICM42670_GYRO, icm42670_gyro_odr[0].odr); + if (ret < 0) { + dev_err(dev, "icm42670_set_odr ICM42670_GYRO failed!\r\n"); + return ret; + } + + ret = icm42670_set_scale(data, ICM42670_ACCEL, + icm42670_accel_scale[0].scale, + icm42670_accel_scale[0].uscale); + if (ret < 0) { + dev_err(dev, "icm42670_set_scale ICM42670_ACCEL failed!\r\n"); + return ret; + } + + ret = icm42670_set_scale(data, ICM42670_GYRO, + icm42670_gyro_scale[0].scale, + icm42670_gyro_scale[0].uscale); + if (ret < 0) { + dev_err(dev, "icm42670_set_scale ICM42670_GYRO failed!\r\n"); + return ret; + } + + ret = regmap_write(data->regmap, REG_INT_CONFIG_REG, data->irq_mask); + if (ret < 0) + return ret; + + dev_info(dev, "icm42670_init success!\r\n"); + + return ret; +} + +int icm42670_core_probe(struct regmap *regmap, + int irq, const char *name, + int chip_type, icm42670_bus_setup bus_setup) +{ + struct iio_dev *indio_dev; + struct icm42670_data *data; + struct device *dev = regmap_get_device(regmap); + int ret; + struct irq_data *desc; + int irq_type; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + memset(data, 0, sizeof(struct icm42670_data)); + mutex_init(&data->lock); + data->chip_type = chip_type; + data->powerup_count = 0; + data->irq = irq; + data->regmap = regmap; + + /* get the node */ + data->node = of_find_node_by_name(NULL, "icm42670"); + if (data->node == NULL) + dev_err(dev, "ic2 node not find!\n"); + + data->int1_gpio = of_get_named_gpio(data->node, "int1-gpio", 0); + if (data->int1_gpio < 0) { + dev_err(dev, "Could not get int1_gpio!\n"); + return -EINVAL; + } + + desc = irq_get_irq_data(irq); + if (!desc) { + dev_err(dev, "Could not find IRQ %d\n", irq); + return -EINVAL; + } + + irq_type = irqd_get_trigger_type(desc); + if (!irq_type) + irq_type = IRQF_TRIGGER_RISING; + + if (irq_type == IRQF_TRIGGER_RISING) { + data->irq_mask = BIT_ONLY_INT1_ACTIVE_HIGH; + } else if (irq_type == IRQF_TRIGGER_FALLING) { + data->irq_mask = BIT_ONLY_INT1_ACTIVE_LOW; + } else { + dev_err(dev, "Invalid interrupt type 0x%x specified\n", + irq_type); + return -EINVAL; + } + + data->vdd_supply = devm_regulator_get(dev, "vcc_3v3_s0"); + if (IS_ERR(data->vdd_supply)) { + dev_err(dev, "Could not find vdd_avdd!\n"); + return PTR_ERR(data->vdd_supply); + } + + ret = regulator_enable(data->vdd_supply); + if (ret) { + dev_err(dev, "regulator_enable failed!\n"); + return ret; + } + + ret = devm_add_action_or_reset(dev, icm42670_disable_vdd_reg, data); + if (ret) { + dev_err(dev, "devm_add_action_or_reset failed!\n"); + return ret; + } + + ret = icm42670_chip_init(data, bus_setup); + if (ret < 0) { + dev_err(dev, "icm42670_chip_init fail\n"); + return ret; + } + + dev_set_drvdata(dev, indio_dev); + if (!name && ACPI_HANDLE(dev)) + name = icm42670_match_acpi_device(dev); + + indio_dev->dev.parent = dev; + indio_dev->channels = icm42670_channels; + indio_dev->num_channels = ARRAY_SIZE(icm42670_channels); + indio_dev->available_scan_masks = icm42670_scan_masks; + indio_dev->name = name; + indio_dev->info = &icm42670_info; + indio_dev->modes = INDIO_BUFFER_TRIGGERED; + + ret = devm_iio_triggered_buffer_setup(dev, indio_dev, iio_pollfunc_store_time, + icm42670_read_fifo, NULL); + if (ret < 0) + goto uninit; + + ret = icm42670_probe_trigger(indio_dev, irq_type); + if (ret) { + dev_err(dev, "trigger probe fail %d\n", ret); + goto uninit; + } + + ret = devm_iio_device_register(dev, indio_dev); + if (ret < 0) { + dev_err(dev, "devm_iio_device_register fail\n"); + goto uninit; + } + + ret = pm_runtime_set_active(dev); + if (ret) + return ret; + + return 0; + +uninit: + icm42670_chip_uninit(data); + return ret; +} +EXPORT_SYMBOL_GPL(icm42670_core_probe); + +/* + * System resume gets the system back on and restores the sensors state. + * Manually put runtime power management in system active state. + */ +static int __maybe_unused sleep_icm42670_resume(struct device *dev) +{ + int ret; + struct icm42670_data *st = iio_priv(dev_get_drvdata(dev)); + struct iio_dev *indio_dev = dev_get_drvdata(dev); + + mutex_lock(&st->lock); + + ret = regulator_enable(st->vdd_supply); + if (ret) + goto out_unlock; + + usleep_range(3000, 4000); + + pm_runtime_disable(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + + icm42670_set_odr(st, ICM42670_GYRO, st->gyro_frequency_buff); + icm42670_set_odr(st, ICM42670_ACCEL, st->accel_frequency_buff); + + ret = icm42670_set_enable(indio_dev, 1); + if (ret) + goto out_unlock; + + devm_regulator_put(st->vdd_supply); +out_unlock: + mutex_unlock(&st->lock); + return ret; +} + +/* + * Suspend saves sensors state and turns everything off. + * Check first if runtime suspend has not already done the job. + */ +static int __maybe_unused sleep_icm42670_suspend(struct device *dev) +{ + struct icm42670_data *st = iio_priv(dev_get_drvdata(dev)); + struct iio_dev *indio_dev = dev_get_drvdata(dev); + int ret; + + mutex_lock(&st->lock); + + st->gyro_frequency_buff = st->gyro_frequency; + st->accel_frequency_buff = st->accel_frequency; + + if (pm_runtime_suspended(dev)) { + ret = 0; + goto out_unlock; + } + + ret = icm42670_set_enable(indio_dev, 0); + if (ret) + goto out_unlock; + + regulator_disable(st->vdd_supply); + devm_regulator_put(st->vdd_supply); + +out_unlock: + mutex_unlock(&st->lock); + return ret; +} + +const struct dev_pm_ops icm42670_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(sleep_icm42670_suspend, sleep_icm42670_resume) +}; +EXPORT_SYMBOL_GPL(icm42670_pm_ops); + +void icm42670_core_remove(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct icm42670_data *data = iio_priv(indio_dev); + + icm42670_chip_uninit(data); +} +EXPORT_SYMBOL_GPL(icm42670_core_remove); + +MODULE_AUTHOR("Hangyu Li "); +MODULE_DESCRIPTION("ICM42670 CORE driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/imu/inv_icm42670/inv_icm42670_i2c.c b/drivers/iio/imu/inv_icm42670/inv_icm42670_i2c.c new file mode 100644 index 000000000000..115adf954c97 --- /dev/null +++ b/drivers/iio/imu/inv_icm42670/inv_icm42670_i2c.c @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2024 Rockchip Electronics Co., Ltd. + */ + +#include "linux/stddef.h" +#include +#include +#include +#include +#include + +#include "inv_icm42670.h" + +static int icm42670_i2c_bus_setup(struct icm42670_data *st) +{ + /* set slew rates for I2C and SPI */ + // TODO + + /* disable SPI bus */ + return regmap_update_bits(st->regmap, REG_INTF_CONFIG0, + BIT_FIFO_COUNT_REC_UI_SIFS_CFG_MASK, + BIT_FIFO_COUNT_REC_UI_SIFS_CFG_SPI_DIS); +} + +static int icm42670_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct regmap *regmap; + const char *name = NULL; + int chip_type = 0; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + dev_err(&client->dev, "I2c function error\n"); + return -EOPNOTSUPP; + } + + if (id) { + chip_type = id->driver_data; + name = id->name; + } + + regmap = devm_regmap_init_i2c(client, &icm42670_regmap_config); + if (IS_ERR(regmap)) { + dev_err(&client->dev, "Failed to register i2c regmap %d\n", + (int)PTR_ERR(regmap)); + return PTR_ERR(regmap); + } + + dev_info(&client->dev, "chip_type = %d, name = %s\n", chip_type, name); + + return icm42670_core_probe(regmap, client->irq, name, chip_type, icm42670_i2c_bus_setup); +} + +static void icm42670_i2c_remove(struct i2c_client *client) +{ + icm42670_core_remove(&client->dev); +} + +static const struct i2c_device_id icm42670_i2c_id[] = { + {"icm42670", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, icm42670_i2c_id); + +static const struct acpi_device_id icm42670_acpi_match[] = { + {"ICM42670", 0}, + { } +}; +MODULE_DEVICE_TABLE(acpi, icm42670_acpi_match); + +#ifdef CONFIG_OF +static const struct of_device_id icm42670_of_match[] = { + { .compatible = "invensense,icm42670" }, + { }, +}; +MODULE_DEVICE_TABLE(of, icm42670_of_match); +#endif + +static struct i2c_driver icm42670_i2c_driver = { + .driver = { + .name = "invensense,icm42670", + .acpi_match_table = ACPI_PTR(icm42670_acpi_match), + .of_match_table = of_match_ptr(icm42670_of_match), + .pm = &icm42670_pm_ops, + }, + .probe = icm42670_i2c_probe, + .remove = icm42670_i2c_remove, + .id_table = icm42670_i2c_id, +}; +module_i2c_driver(icm42670_i2c_driver); + +MODULE_AUTHOR("Hangyu Li "); +MODULE_DESCRIPTION("ICM42670 I2C driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/imu/inv_icm42670/inv_icm42670_ring.c b/drivers/iio/imu/inv_icm42670/inv_icm42670_ring.c new file mode 100644 index 000000000000..1dbddb85f217 --- /dev/null +++ b/drivers/iio/imu/inv_icm42670/inv_icm42670_ring.c @@ -0,0 +1,244 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2024 Rockchip Electronics Co., Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "inv_icm42670.h" + +/** + * icm42670_update_period() - Update chip internal period estimation + * + * @st: driver state + * @timestamp: the interrupt timestamp + * @nb: number of data set in the fifo + * + * This function uses interrupt timestamps to estimate the chip period and + * to choose the data timestamp to come. + */ +static void icm42670_update_period(struct icm42670_data *st, + s64 timestamp, size_t nb) +{ + s64 interval; + + if (st->it_timestamp != 0) + st->interrupt_period = div_s64((timestamp - st->it_timestamp), nb); + + interval = (nb - 1) * st->interrupt_period; + st->data_timestamp = timestamp - interval; + /* save it timestamp */ + st->it_timestamp = timestamp; +} + +/** + * icm42670_get_timestamp() - Return the current data timestamp + * + * @st: driver state + * @return: current data timestamp + * + * This function returns the current data timestamp and prepares for next one. + */ +static s64 icm42670_get_timestamp(struct icm42670_data *st) +{ + s64 ts; + + /* return current data timestamp and increment */ + ts = st->data_timestamp; + st->data_timestamp += st->interrupt_period; + + return ts; +} + +int icm42670_reset_fifo(struct iio_dev *indio_dev) +{ + int ret; + struct icm42670_data *st = iio_priv(indio_dev); + const struct device *dev = regmap_get_device(st->regmap); + + /* reset it timestamp validation */ + st->it_timestamp = 0; + + /* Before setting the FIFO water level, make sure the interrupt source is disabled. */ + ret = regmap_write(st->regmap, REG_INT_SOURCE0, BIT_INT_MODE_OFF); + if (ret) { + dev_err(dev, "int_enable failed %d\n", + ret); + goto reset_fifo_fail; + } + + /* disable the sensor output to FIFO */ + ret = regmap_write(st->regmap, REG_FIFO_CONFIG1, BIT_FIFO_MODE_BYPASS); + if (ret) { + dev_err(dev, "Failed to write to REG_FIFO_CONFIG1 register!\n"); + goto reset_fifo_fail; + } + + /* reset FIFO*/ + ret = regmap_update_bits(st->regmap, REG_SIGNAL_PATH_RESET, + BIT_FIFO_FLUSH, BIT_FIFO_FLUSH); + if (ret) { + dev_err(dev, "Failed to write to REG_SIGNAL_PATH_RESET register!\n"); + goto reset_fifo_fail; + } + ndelay(1500); //wait for 1.5us + + /* enable sensor output to FIFO */ + ret = regmap_write(st->regmap, REG_FIFO_CONFIG1, + BIT_FIFO_MODE_NO_BYPASS | BIT_FIFO_MODE_STOPFULL); + if (ret) { + dev_err(dev, "Failed to write to REG_FIFO_CONFIG1 register!\n"); + goto reset_fifo_fail; + } + + ret = icm42670_mreg_single_write(st, REG_TMST_CONFIG1_MREG_TOP1, + BIT_TMST_EN | BIT_TMST_FSYNC_EN); + if (ret) { + dev_err(dev, "Failed to write to REG_TMST_CONFIG1_MREG_TOP1 register!\n"); + goto reset_fifo_fail; + } + + /* + * FIFO_COUNT_FORMAT setting. FIFO_WM_EN must be zero before writing this register. + * Interrupt only fires once. This register should be set to nonzero value, + * before choosing this interrupt source. + * This field should be changed when FIFO is empty to avoid spurious interrupts + */ + ret = regmap_write(st->regmap, REG_FIFO_CONFIG2, BIT_FIFO_WM5); + if (ret) { + dev_err(dev, "Failed to write to REG_FIFO_CONFIG2 register!\n"); + goto reset_fifo_fail; + } + + ret = icm42670_mreg_single_write(st, REG_FIFO_CONFIG5_MREG_TOP1, + BIT_WM_GT_TH | BIT_FIFO_ACCEL_EN | + BIT_FIFO_GYRO_EN | BIT_FIFO_TMST_FSYNC_EN); + if (ret) { + dev_err(dev, "Failed to write to REG_FIFO_CONFIG5_MREG_TOP1 register!\n"); + goto reset_fifo_fail; + } + + /* Set FIFO interrupt source to INT1*/ + ret = regmap_write(st->regmap, REG_INT_SOURCE0, + BIT_INT_RESET_DONE_INT1_EN | BIT_INT_FIFO_THS_INT1_EN); + if (ret) { + dev_err(dev, "Failed to write to REG_INT_SOURCE0 register!\n"); + goto reset_fifo_fail; + } + + st->interrupt_period = st->standard_period; + + return 0; + +reset_fifo_fail: + dev_err(regmap_get_device(st->regmap), "%s :reset fifo failed %d\n", __func__, ret); + ret = regmap_write(st->regmap, REG_INT_SOURCE0, + BIT_INT_RESET_DONE_INT1_EN | BIT_INT_FIFO_THS_INT1_EN); + + return ret; +} + +/** + * icm42670_read_fifo() - Transfer data from hardware FIFO to KFIFO. + */ +irqreturn_t icm42670_read_fifo(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct icm42670_data *st = iio_priv(indio_dev); + const struct device *dev = regmap_get_device(st->regmap); + size_t bytes_per_datum; + int result, int_status, int_drdy; + u8 data[ICM42670_OUTPUT_DATA_SIZE_PULS_ONE], i; + u16 fifo_count; + u32 data_len; + s64 timestamp = 0; + + mutex_lock(&st->lock); + + /* ack interrupt and check status */ + result = regmap_read(st->regmap, REG_INT_STATUS, &int_status); + if (result) { + dev_err(dev, "failed to ack interrupt\n"); + goto flush_fifo; + } + + result = regmap_read(st->regmap, REG_INT_STATUS_DRDY, &int_drdy); + if (result) { + dev_err(dev, "failed to ack interrupt\n"); + goto flush_fifo; + } + + if (!(int_status & BIT_INT_STATUS_FIFO_THS)) { + dev_warn(dev, "spurious interrupt with status 0x%x\n", int_status); + if (!(int_drdy & (BIT_INT_STATUS_DRDY))) + goto flush_fifo; + } + + if ((int_status & BIT_INT_STATUS_FIFO_FULL)) { + dev_warn(dev, "the fifo is full\n"); + goto flush_fifo; + } + + bytes_per_datum = ICM42670_FIFO_DATUM; + result = regmap_bulk_read(st->regmap, REG_FIFO_BYTE_COUNT1, + data, ICM42670_FIFO_COUNT_BYTE); + if (result) { + dev_err(dev, "read fifo count fail: %d\n", result); + goto end_session; + } + + fifo_count = get_unaligned_be16(&data[0]); + if (fifo_count > ICM42670_FIFO_COUNT_LIMIT) { + dev_warn(dev, "fifo overflow reset, cnt: %u\n", fifo_count); + goto flush_fifo; + } + + icm42670_update_period(st, pf->timestamp, fifo_count); + + data_len = bytes_per_datum * fifo_count; + + result = regmap_bulk_read(st->regmap, REG_FIFO_DATA_REG, + st->data_buff, data_len); + if (result) { + dev_err(dev, + "regmap_bulk_read failed\n"); + goto flush_fifo; + } + + for (i = 0; i < fifo_count; ++i) { + /* skip first samples if needed */ + if (st->skip_samples) { + st->skip_samples--; + continue; + } + memcpy(data, st->data_buff+i*16, bytes_per_datum); + timestamp = icm42670_get_timestamp(st); + iio_push_to_buffers_with_timestamp(indio_dev, &(data[1]), timestamp); + } + +end_session: + mutex_unlock(&st->lock); + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; + +flush_fifo: + /* Flush HW and SW FIFOs. */ + dev_info(dev, "flush info\n"); + icm42670_reset_fifo(indio_dev); + mutex_unlock(&st->lock); + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} diff --git a/drivers/iio/imu/inv_icm42670/inv_icm42670_spi.c b/drivers/iio/imu/inv_icm42670/inv_icm42670_spi.c new file mode 100644 index 000000000000..915d1231e110 --- /dev/null +++ b/drivers/iio/imu/inv_icm42670/inv_icm42670_spi.c @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2024 Rockchip Electronics Co., Ltd. + */ + +#include "linux/stddef.h" +#include +#include +#include +#include +#include + +#include "inv_icm42670.h" + +static int icm42670_spi_bus_setup(struct icm42670_data *st) +{ + /* set slew rates for I2C and SPI */ + // TODO + + /* disable I2C bus */ + return regmap_update_bits(st->regmap, REG_INTF_CONFIG0, + BIT_FIFO_COUNT_REC_UI_SIFS_CFG_MASK, + BIT_FIFO_COUNT_REC_UI_SIFS_CFG_I2C_DIS); +} + +static int icm42670_spi_probe(struct spi_device *spi) +{ + struct regmap *regmap; + const char *name = NULL; + int chip_type = 0; + const struct spi_device_id *id = spi_get_device_id(spi); + + if (id) { + chip_type = id->driver_data; + name = id->name; + } + + regmap = devm_regmap_init_spi(spi, &icm42670_regmap_config); + if (IS_ERR(regmap)) { + dev_err(&spi->dev, "Failed to register spi regmap %d\n", + (int)PTR_ERR(regmap)); + return PTR_ERR(regmap); + } + + dev_info(&spi->dev, "chip_type = %d, name = %s\n", chip_type, name); + + return icm42670_core_probe(regmap, spi->irq, name, chip_type, icm42670_spi_bus_setup); +} + +static void icm42670_spi_remove(struct spi_device *spi) +{ + icm42670_core_remove(&spi->dev); +} + +static const struct spi_device_id icm42670_spi_id[] = { + {"icm42670", 0}, + {} +}; +MODULE_DEVICE_TABLE(spi, icm42670_spi_id); + +static const struct acpi_device_id icm42670_acpi_match[] = { + {"ICM42670", 0}, + { } +}; +MODULE_DEVICE_TABLE(acpi, icm42670_acpi_match); + +#ifdef CONFIG_OF +static const struct of_device_id icm42670_of_match[] = { + { .compatible = "invensense,icm42670" }, + { }, +}; +MODULE_DEVICE_TABLE(of, icm42670_of_match); +#endif + +static struct spi_driver icm42670_spi_driver = { + .driver = { + .name = "invensense,icm42670", + .acpi_match_table = ACPI_PTR(icm42670_acpi_match), + .of_match_table = of_match_ptr(icm42670_of_match), + .pm = &icm42670_pm_ops, + }, + .probe = icm42670_spi_probe, + .remove = icm42670_spi_remove, + .id_table = icm42670_spi_id, +}; +module_spi_driver(icm42670_spi_driver); + +MODULE_AUTHOR("Hangyu Li "); +MODULE_DESCRIPTION("ICM42670 SPI driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/imu/inv_icm42670/inv_icm42670_trigger.c b/drivers/iio/imu/inv_icm42670/inv_icm42670_trigger.c new file mode 100644 index 000000000000..8b52eca60738 --- /dev/null +++ b/drivers/iio/imu/inv_icm42670/inv_icm42670_trigger.c @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2024 Rockchip Electronics Co., Ltd. + */ + +#include "inv_icm42670.h" +#include + +/** + * icm42670_set_enable() - enable chip functions. + * @indio_dev: Device driver instance. + * @enable: enable/disable + */ +int icm42670_set_enable(struct iio_dev *indio_dev, bool enable) +{ + int ret; + struct icm42670_data *data = iio_priv(indio_dev); + const struct device *dev = regmap_get_device(data->regmap); + + if (enable) { + ret = icm42670_set_mode(data, ICM42670_ACCEL, true); + if (ret) + goto error_off; + + ret = icm42670_set_mode(data, ICM42670_GYRO, true); + if (ret) + goto error_accl_off; + + ret = icm42670_reset_fifo(indio_dev); + if (ret) + goto error_gyro_off; + + /* Theoretical interrupt period */ + data->standard_period = data->period_divider > 0 ? + div_s64(NSEC_PER_SEC, data->period_divider) : + NSEC_PER_USEC * data->period_divider * (-1); + + data->interrupt_period = data->standard_period; + + /* Set a floating range of 4% */ + data->period_min = div_s64((data->standard_period * (100 - + ICM42670_TS_PERIOD_JITTER)), 100); + data->period_max = div_s64((data->standard_period * (100 + + ICM42670_TS_PERIOD_JITTER)), 100); + } else { + ret = regmap_write(data->regmap, REG_FIFO_CONFIG1, BIT_FIFO_MODE_BYPASS); + if (ret) { + dev_err(dev, "set REG_FIFO_CONFIG1 fail: %d\n", ret); + goto error_gyro_off; + } + ret = icm42670_set_mode(data, ICM42670_GYRO, false); + if (ret) + goto error_gyro_off; + + ret = icm42670_set_mode(data, ICM42670_ACCEL, false); + if (ret) + goto error_accl_off; + } + dev_info(dev, "set fifo mode end\n"); + return ret; + +error_gyro_off: + icm42670_set_mode(data, ICM42670_GYRO, false); +error_accl_off: + icm42670_set_mode(data, ICM42670_ACCEL, false); +error_off: + return ret; +} + +/** + * inv_mpu_data_rdy_trigger_set_state() - set data ready interrupt state + * @trig: Trigger instance + * @state: Desired trigger state + */ +static int inv_mpu_data_rdy_trigger_set_state(struct iio_trigger *trig, + bool state) +{ + struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); + struct icm42670_data *data = iio_priv(indio_dev); + int result; + + mutex_lock(&data->lock); + dev_info(regmap_get_device(data->regmap), "in data_rdy_trigger_set_state, %d\n", state); + result = icm42670_set_enable(indio_dev, state); + mutex_unlock(&data->lock); + + return result; +} + +static const struct iio_trigger_ops inv_mpu_trigger_ops = { + .set_trigger_state = &inv_mpu_data_rdy_trigger_set_state, +}; + +int icm42670_probe_trigger(struct iio_dev *indio_dev, int irq_type) +{ + int ret; + struct icm42670_data *data = iio_priv(indio_dev); + + data->trig = devm_iio_trigger_alloc(&indio_dev->dev, + "%s-dev%d", + indio_dev->name, + iio_device_id(indio_dev)); + if (!data->trig) + return -ENOMEM; + + ret = devm_request_irq(&indio_dev->dev, data->irq, + &iio_trigger_generic_data_rdy_poll, + irq_type, + "inv_mpu", + data->trig); + if (ret) + return ret; + + data->trig->dev.parent = regmap_get_device(data->regmap); + data->trig->ops = &inv_mpu_trigger_ops; + iio_trigger_set_drvdata(data->trig, indio_dev); + + ret = devm_iio_trigger_register(&indio_dev->dev, data->trig); + if (ret) + return ret; + + indio_dev->trig = iio_trigger_get(data->trig); + + return 0; +} From 711f17c2fe8f80e0f9aa03b8f2c7ce2c5b21e6ff Mon Sep 17 00:00:00 2001 From: Yu Qiaowei Date: Wed, 4 Dec 2024 20:07:22 +0800 Subject: [PATCH 04/15] video: rockchip: rga3: fix intr exception that causes driver timeout Signed-off-by: Yu Qiaowei Change-Id: I1ca23d1ef4ffd88244224bc463afc7d5e192e292 --- drivers/video/rockchip/rga3/rga_job.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/video/rockchip/rga3/rga_job.c b/drivers/video/rockchip/rga3/rga_job.c index 2a1a16e5a640..2acbb9d9596d 100644 --- a/drivers/video/rockchip/rga3/rga_job.c +++ b/drivers/video/rockchip/rga3/rga_job.c @@ -234,7 +234,8 @@ struct rga_job *rga_job_done(struct rga_scheduler_t *scheduler) return NULL; } - if (!test_bit(RGA_JOB_STATE_FINISH, &job->state)) { + if (!test_bit(RGA_JOB_STATE_FINISH, &job->state) && + !test_bit(RGA_JOB_STATE_INTR_ERR, &job->state)) { rga_err("%s(%#x) running job has not yet been completed.", rga_get_core_name(scheduler->core), scheduler->core); From 971dce993d3075b927b6ca393d0c9dcb9532c62f Mon Sep 17 00:00:00 2001 From: Yu Qiaowei Date: Thu, 5 Dec 2024 11:39:16 +0800 Subject: [PATCH 05/15] video: rockchip: rga3: fix bi-linear scaled down causing timeout Adjust config based on RGA2 limit. Update driver version to 1.3.7 Signed-off-by: Yu Qiaowei Change-Id: I2954dbb36a1698e34da14fff33fb9d97792478da --- .../rockchip/rga3/include/rga2_reg_info.h | 13 ++- drivers/video/rockchip/rga3/include/rga_drv.h | 2 +- drivers/video/rockchip/rga3/rga2_reg_info.c | 79 ++++++++++++++++--- 3 files changed, 79 insertions(+), 15 deletions(-) diff --git a/drivers/video/rockchip/rga3/include/rga2_reg_info.h b/drivers/video/rockchip/rga3/include/rga2_reg_info.h index cca8a20b16b2..4afac19b0a16 100644 --- a/drivers/video/rockchip/rga3/include/rga2_reg_info.h +++ b/drivers/video/rockchip/rga3/include/rga2_reg_info.h @@ -292,11 +292,15 @@ /* RGA_SRC_ACT_INFO */ -#define m_RGA2_SRC_ACT_INFO_SW_SRC_ACT_WIDTH (0x1fff << 0) -#define m_RGA2_SRC_ACT_INFO_SW_SRC_ACT_HEIGHT (0x1fff << 16) +#define m_RGA2_SRC_ACT_INFO_SW_TILE4X4_IN_YOFF (0x3 << 30) +#define m_RGA2_SRC_ACT_INFO_SW_SRC_ACT_HEIGHT (0x7ff << 16) +#define m_RGA2_SRC_ACT_INFO_SW_TILE4X4_IN_XOFF (0x3 << 14) +#define m_RGA2_SRC_ACT_INFO_SW_SRC_ACT_WIDTH (0x7ff << 0) -#define s_RGA2_SRC_ACT_INFO_SW_SRC_ACT_WIDTH(x) ((x & 0x1fff) << 0) -#define s_RGA2_SRC_ACT_INFO_SW_SRC_ACT_HEIGHT(x) ((x & 0x1fff) << 16) +#define s_RGA2_SRC_ACT_INFO_SW_TILE4X4_IN_YOFF(x) ((x & 0x3) << 30) +#define s_RGA2_SRC_ACT_INFO_SW_SRC_ACT_HEIGHT(x) ((x & 0x7ff) << 16) +#define s_RGA2_SRC_ACT_INFO_SW_TILE4X4_IN_XOFF(x) ((x & 0x3) << 14) +#define s_RGA2_SRC_ACT_INFO_SW_SRC_ACT_WIDTH(x) ((x & 0x7ff) << 0) /* RGA2_OSD_CTRL0 */ #define m_RGA2_OSD_CTRL0_SW_OSD_MODE (0x3 << 0) @@ -480,6 +484,7 @@ #define s_RGA2_MMU_CTRL1_SW_ELS_MMU_FLUSH(x) ((x & 0x1) << 13) #define RGA2_VSP_BICUBIC_LIMIT 1996 +#define RGA2_BILINEAR_PREC 12 union rga2_color_ctrl { uint32_t value; diff --git a/drivers/video/rockchip/rga3/include/rga_drv.h b/drivers/video/rockchip/rga3/include/rga_drv.h index 9c5688107542..e0c34bb4aa7e 100644 --- a/drivers/video/rockchip/rga3/include/rga_drv.h +++ b/drivers/video/rockchip/rga3/include/rga_drv.h @@ -88,7 +88,7 @@ #define DRIVER_MAJOR_VERISON 1 #define DRIVER_MINOR_VERSION 3 -#define DRIVER_REVISION_VERSION 6 +#define DRIVER_REVISION_VERSION 7 #define DRIVER_PATCH_VERSION #define DRIVER_VERSION (STR(DRIVER_MAJOR_VERISON) "." STR(DRIVER_MINOR_VERSION) \ diff --git a/drivers/video/rockchip/rga3/rga2_reg_info.c b/drivers/video/rockchip/rga3/rga2_reg_info.c index 49523d5d7e95..aa918ac5b92f 100644 --- a/drivers/video/rockchip/rga3/rga2_reg_info.c +++ b/drivers/video/rockchip/rga3/rga2_reg_info.c @@ -101,17 +101,52 @@ unsigned int rga2_rop_code[256] = { 0x00000051, 0x008004d4, 0x00800451, 0x00800007,//f }; +static void rga2_scale_down_bilinear_protect(u32 *param_fix, u32 *src_fix, + u32 param, u32 offset, u32 src, u32 dst) +{ + int final_coor, final_diff, final_steps; + + while (1) { + final_coor = offset + param * (dst - 1); + final_diff = (src - 1) * (1 << RGA2_BILINEAR_PREC) - final_coor; + + /* + * The hardware requires that the last point of the dst map on + * src must not exceed the range of src. + */ + if (final_diff <= 0) + param = param - 1; + else + break; + } + + /* + * The hardware requires that the last point of dst mapping on + * src be between the last two points of each row/column, so + * actual width/height needs to be modified. + */ + final_steps = (final_coor & ((1 << RGA2_BILINEAR_PREC) - 1)) ? + ((final_coor >> RGA2_BILINEAR_PREC) + 1) : + (final_coor >> RGA2_BILINEAR_PREC); + + *param_fix = param; + *src_fix = final_steps + 1; +} + static void RGA2_reg_get_param(unsigned char *base, struct rga2_req *msg) { u32 *bRGA_SRC_X_FACTOR; u32 *bRGA_SRC_Y_FACTOR; + u32 *bRGA_SRC_ACT_INFO; u32 sw, sh; u32 dw, dh; u32 param_x, param_y; u32 scale_x_offset, scale_y_offset; + u32 src_fix, param_fix; bRGA_SRC_X_FACTOR = (u32 *) (base + RGA2_SRC_X_FACTOR_OFFSET); bRGA_SRC_Y_FACTOR = (u32 *) (base + RGA2_SRC_Y_FACTOR_OFFSET); + bRGA_SRC_ACT_INFO = (u32 *) (base + RGA2_SRC_ACT_INFO_OFFSET); if (((msg->rotate_mode & 0x3) == 1) || ((msg->rotate_mode & 0x3) == 3)) { @@ -128,10 +163,24 @@ static void RGA2_reg_get_param(unsigned char *base, struct rga2_req *msg) if (sw > dw) { if (msg->interp.horiz == RGA_INTERP_LINEAR) { /* default to half_pixel mode. */ - param_x = (sw << 12) / dw; - scale_x_offset = 0x1ff; + param_x = (sw << RGA2_BILINEAR_PREC) / dw; + scale_x_offset = (1 << RGA2_BILINEAR_PREC) >> 1; - *bRGA_SRC_X_FACTOR = ((param_x & 0xffff) | ((scale_x_offset) << 16)); + rga2_scale_down_bilinear_protect(¶m_fix, &src_fix, + param_x, scale_x_offset, sw, dw); + if (DEBUGGER_EN(MSG)) { + if (param_x != param_fix) + rga_log("scale: Bi-linear horiz factor %#x fix to %#x\n", + param_x, param_fix); + if (sw != src_fix) + rga_log("scale: Bi-linear src_width %d -> %d\n", + sw, src_fix); + } + + *bRGA_SRC_X_FACTOR = ((param_fix & 0xffff) | ((scale_x_offset) << 16)); + *bRGA_SRC_ACT_INFO = + ((*bRGA_SRC_ACT_INFO & (~m_RGA2_SRC_ACT_INFO_SW_SRC_ACT_WIDTH)) | + s_RGA2_SRC_ACT_INFO_SW_SRC_ACT_WIDTH((src_fix - 1))); } else { param_x = ((dw << 16) + (sw / 2)) / sw; @@ -151,10 +200,24 @@ static void RGA2_reg_get_param(unsigned char *base, struct rga2_req *msg) if (sh > dh) { if (msg->interp.verti == RGA_INTERP_LINEAR) { /* default to half_pixel mode. */ - param_y = (sh << 12) / dh; - scale_y_offset = 0x1ff; + param_y = (sh << RGA2_BILINEAR_PREC) / dh; + scale_y_offset = (1 << RGA2_BILINEAR_PREC) >> 1; - *bRGA_SRC_Y_FACTOR = ((param_y & 0xffff) | ((scale_y_offset) << 16)); + rga2_scale_down_bilinear_protect(¶m_fix, &src_fix, + param_y, scale_y_offset, sh, dh); + if (DEBUGGER_EN(MSG)) { + if (param_y != param_fix) + rga_log("scale: Bi-linear verti factor %#x fix to %#x\n", + param_y, param_fix); + if (sh != src_fix) + rga_log("scale: Bi-linear src_height %d fix to %d\n", + sh, src_fix); + } + + *bRGA_SRC_Y_FACTOR = ((param_fix & 0xffff) | ((scale_y_offset) << 16)); + *bRGA_SRC_ACT_INFO = + ((*bRGA_SRC_ACT_INFO & (~m_RGA2_SRC_ACT_INFO_SW_SRC_ACT_HEIGHT)) | + s_RGA2_SRC_ACT_INFO_SW_SRC_ACT_HEIGHT((src_fix - 1))); } else { param_y = ((dh << 16) + (sh / 2)) / sh; @@ -363,10 +426,6 @@ static void RGA2_set_reg_src_info(u8 *base, struct rga2_req *msg) vsd_scale_mode = 0; break; case RGA_INTERP_LINEAR: - if (sh > 4096) - /* force select average */ - vsd_scale_mode = 0; - else vsd_scale_mode = 1; break; From 70e0b8e2147e53529095e6e32ed335b940301d8a Mon Sep 17 00:00:00 2001 From: Yifeng Zhao Date: Wed, 30 Oct 2024 11:00:51 +0800 Subject: [PATCH 06/15] scsi: ufs: rockchip: fix dme-reset failed issue Resetting the device without resetting the controller during exception handling will result in a dme command error. log: ufshcd-rockchip 2a2d0000.ufs: uic cmd 0x14 with arg3 0x0 completion timeout ufshcd-rockchip 2a2d0000.ufs: dme-reset: error code -110 ufshcd-rockchip 2a2d0000.ufs: DME_RESET failed ufshcd-rockchip 2a2d0000.ufs: ufshcd_host_reset_and_restore: Host init failed -110 Change-Id: Ia83e80aea0f6b916bf7131d0b2240023f32a1a21 Signed-off-by: Yifeng Zhao --- drivers/ufs/host/ufs-rockchip.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/ufs/host/ufs-rockchip.c b/drivers/ufs/host/ufs-rockchip.c index 53104cceb299..e7a3191cb4b2 100644 --- a/drivers/ufs/host/ufs-rockchip.c +++ b/drivers/ufs/host/ufs-rockchip.c @@ -182,14 +182,25 @@ static int ufshcd_dme_link_startup(struct ufs_hba *hba) return ret; } +static void ufs_rockchip_controller_reset(struct ufs_rockchip_host *host) +{ + reset_control_assert(host->rst); + udelay(1); + reset_control_deassert(host->rst); +} + static int ufs_rockchip_hce_enable_notify(struct ufs_hba *hba, enum ufs_notify_change_status status) { + struct ufs_rockchip_host *host = ufshcd_get_variant(hba); int err = 0; if (status == PRE_CHANGE) { int retry_outer = 3; int retry_inner; + + ufs_rockchip_controller_reset(host); + start: if (ufshcd_is_hba_active(hba)) /* change controller state to "reset state" */ @@ -374,9 +385,7 @@ static int ufs_rockchip_common_init(struct ufs_hba *hba) return PTR_ERR(host->rst); } - reset_control_assert(host->rst); - udelay(1); - reset_control_deassert(host->rst); + ufs_rockchip_controller_reset(host); host->ref_out_clk = devm_clk_get(dev, "ref_out"); if (IS_ERR(host->ref_out_clk)) { From b769d72b955fd87d8ac60fd538e2a20143fa54c9 Mon Sep 17 00:00:00 2001 From: Yifeng Zhao Date: Tue, 3 Dec 2024 10:19:47 +0800 Subject: [PATCH 07/15] scsi: ufs: rockchip: disabled devfreq for rk3576 log: ufshcd-rockchip 2a2d0000.ufs: ufshcd_wait_for_doorbell_clr: timedout waiting for doorbell to clear (tm=0x0, tr=0x2) devfreq 2a2d0000.ufs: dvfs failed with (-16) error Signed-off-by: Yifeng Zhao Change-Id: Ibc4b07b8ccefcc64220aa108caf51d938b7377dc --- drivers/ufs/host/ufs-rockchip.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/ufs/host/ufs-rockchip.c b/drivers/ufs/host/ufs-rockchip.c index e7a3191cb4b2..4b0fd9726522 100644 --- a/drivers/ufs/host/ufs-rockchip.c +++ b/drivers/ufs/host/ufs-rockchip.c @@ -450,8 +450,6 @@ static int ufs_rockchip_rk3576_init(struct ufs_hba *hba) hba->caps |= UFSHCD_CAP_AUTO_BKOPS_SUSPEND; /* Enable putting device into deep sleep */ hba->caps |= UFSHCD_CAP_DEEPSLEEP; - /* Enable devfreq of UFS */ - hba->caps |= UFSHCD_CAP_CLK_SCALING; /* Enable WriteBooster */ hba->caps |= UFSHCD_CAP_WB_EN; From d84e5b6f720fe8556f2cab573b4f8549b4812f45 Mon Sep 17 00:00:00 2001 From: Yifeng Zhao Date: Tue, 3 Dec 2024 10:24:51 +0800 Subject: [PATCH 08/15] arm64: dts: rockchip: rk3576: remove freq table for ufs Design frequency is 166MHz, overclocking may cause stability issues. Signed-off-by: Yifeng Zhao Change-Id: Ia0b4bf630c1033badc6ca23bd5b0af9b2c9b2eb7 --- arch/arm64/boot/dts/rockchip/rk3576.dtsi | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm64/boot/dts/rockchip/rk3576.dtsi b/arch/arm64/boot/dts/rockchip/rk3576.dtsi index 3750ddb2ad0a..9dd309efd801 100644 --- a/arch/arm64/boot/dts/rockchip/rk3576.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3576.dtsi @@ -4785,7 +4785,6 @@ <&cru CLK_REF_UFS_CLKOUT>; clock-names = "core", "pclk", "pclk_mphy", "ref_out"; - freq-table-hz = <50000000 250000000>, <0 0>, <0 0>, <0 0>; assigned-clocks = <&cru CLK_REF_OSC_MPHY>; assigned-clock-parents = <&cru CLK_REF_MPHY_26M>; interrupts = ; From 4d970531648b069cb3c4a00156ebab04d0c697c5 Mon Sep 17 00:00:00 2001 From: Yifeng Zhao Date: Wed, 20 Nov 2024 17:38:58 +0800 Subject: [PATCH 09/15] mmc: cqhci: add emmc hardware reset after cqe recovery When an eMMC error occurs due to changes in hardware conditions (such as temperature, voltage, etc.), it may not return to normal without reinitializing the eMMC. In this case, adding hardware reset and reinitialization can solve the problem. Change-Id: Ie2164175c59402d06fcb0d774aaba6d712f947d9 Signed-off-by: Yifeng Zhao --- drivers/mmc/host/cqhci-core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/mmc/host/cqhci-core.c b/drivers/mmc/host/cqhci-core.c index c14d7251d0bb..6db5bf147525 100644 --- a/drivers/mmc/host/cqhci-core.c +++ b/drivers/mmc/host/cqhci-core.c @@ -1120,6 +1120,9 @@ static void cqhci_recovery_finish(struct mmc_host *mmc) cqhci_set_irqs(cq_host, CQHCI_IS_MASK); + /* Add emmc hardware reset after cqe recovery. */ + mmc_hw_reset(mmc->card); + pr_debug("%s: cqhci: recovery done\n", mmc_hostname(mmc)); } From 049257ee6692b46b2808863931c31c2db16287db Mon Sep 17 00:00:00 2001 From: XiaoDong Huang Date: Thu, 12 Dec 2024 15:02:17 +0800 Subject: [PATCH 10/15] dt-bindings: suspend: rk3588: add sleep-pin related macros Signed-off-by: XiaoDong Huang Change-Id: Ib2dfcf71646d363cc2d4aa0adb9a9e1f339a53a1 --- include/dt-bindings/suspend/rockchip-rk3588.h | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/include/dt-bindings/suspend/rockchip-rk3588.h b/include/dt-bindings/suspend/rockchip-rk3588.h index 0dd63241c9a6..f623e57420ce 100644 --- a/include/dt-bindings/suspend/rockchip-rk3588.h +++ b/include/dt-bindings/suspend/rockchip-rk3588.h @@ -62,4 +62,26 @@ #define RKPM_VCCIO5_RET_EN BIT(5) #define RKPM_VCCIO6_RET_EN BIT(6) #define RKPM_PMUIO2_RET_EN BIT(7) + +/* sleep pin */ +#define RKPM_SLEEP_PIN0_ACT_LOW BIT(0) /* GPIO0_A2 */ +#define RKPM_SLEEP_PIN1_ACT_LOW BIT(1) /* GPIO0_A3 */ + +#define RKPM_SLEEP_PIN_SRC_VD_NPU 0x1 +#define RKPM_SLEEP_PIN_SRC_VD_GPU 0x2 +#define RKPM_SLEEP_PIN_SRC_VD_BIGCORE0 0x3 +#define RKPM_SLEEP_PIN_SRC_VD_BIGCORE1 0x4 +#define RKPM_SLEEP_PIN_SRC_VD_DSU 0x5 +#define RKPM_SLEEP_PIN_SRC_VD_VCODEC 0x6 +#define RKPM_SLEEP_PIN_SRC_VD_DDR 0x7 +#define RKPM_SLEEP_PIN_SRC_LP_DEEP_LP 0x8 +#define RKPM_SLEEP_PIN_SRC_SFT_EN 0xf + +#define RKPM_SLEEP_PIN0_SRC(n) (((n) & 0xf) << 0) +#define RKPM_SLEEP_PIN1_SRC(n) (((n) & 0xf) << 4) +#define RKPM_SLEEP_PIN2_SRC(n) (((n) & 0xf) << 8) +#define RKPM_SLEEP_PIN3_SRC(n) (((n) & 0xf) << 12) +#define RKPM_SLEEP_PIN4_SRC(n) (((n) & 0xf) << 16) +#define RKPM_SLEEP_PIN5_SRC(n) (((n) & 0xf) << 20) + #endif From 0b991abdb470689c69377f8d4d25054caa70ba86 Mon Sep 17 00:00:00 2001 From: XiaoDong Huang Date: Fri, 13 Dec 2024 17:44:17 +0800 Subject: [PATCH 11/15] dt-bindings: suspend: rk3588: add RKPM_SLP_ARCH_TIMER_RESET macro Signed-off-by: XiaoDong Huang Change-Id: Ibc34b83dcb436223deca7049f9659a6c4c0b2107 --- include/dt-bindings/suspend/rockchip-rk3588.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/dt-bindings/suspend/rockchip-rk3588.h b/include/dt-bindings/suspend/rockchip-rk3588.h index f623e57420ce..f1263079bee3 100644 --- a/include/dt-bindings/suspend/rockchip-rk3588.h +++ b/include/dt-bindings/suspend/rockchip-rk3588.h @@ -31,6 +31,7 @@ #define RKPM_SLP_32K_EXT BIT(24) #define RKPM_SLP_TIME_OUT_WKUP BIT(25) #define RKPM_SLP_PMU_DBG BIT(26) +#define RKPM_SLP_ARCH_TIMER_RESET BIT(27) /* the wake up source */ #define RKPM_CPU0_WKUP_EN BIT(0) From 446d978b3e76fcbb898fc58b07ef56a28964f92c Mon Sep 17 00:00:00 2001 From: XiaoDong Huang Date: Fri, 13 Dec 2024 17:43:52 +0800 Subject: [PATCH 12/15] dt-bindings: suspend: rk3576: add RKPM_SLP_ARCH_TIMER_RESET macro Signed-off-by: XiaoDong Huang Change-Id: Ic1c1e1e5a062e0c681b2633c37a204da3fe24142 --- include/dt-bindings/suspend/rockchip-rk3576.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/dt-bindings/suspend/rockchip-rk3576.h b/include/dt-bindings/suspend/rockchip-rk3576.h index e351254b5d64..84a2f2517e9c 100644 --- a/include/dt-bindings/suspend/rockchip-rk3576.h +++ b/include/dt-bindings/suspend/rockchip-rk3576.h @@ -31,6 +31,7 @@ #define RKPM_SLP_32K_EXT BIT(24) #define RKPM_SLP_TIME_OUT_WKUP BIT(25) #define RKPM_SLP_PMU_DBG BIT(26) +#define RKPM_SLP_ARCH_TIMER_RESET BIT(27) /* the wake up source */ #define RKPM_CPU0_WKUP_EN BIT(0) From 5823f0f49c184278c0d3d0f22d8f18385746f202 Mon Sep 17 00:00:00 2001 From: Shunhua Lan Date: Thu, 28 Nov 2024 15:38:49 +0800 Subject: [PATCH 13/15] ASoC: rockchip: multicodecs: checking hp status when resume from sleep Signed-off-by: Shunhua Lan Change-Id: Ia5def71bba47be20f61fff3f03de42d627aa411a --- sound/soc/rockchip/rockchip_multicodecs.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/sound/soc/rockchip/rockchip_multicodecs.c b/sound/soc/rockchip/rockchip_multicodecs.c index 9e346f105fae..04fc84311728 100644 --- a/sound/soc/rockchip/rockchip_multicodecs.c +++ b/sound/soc/rockchip/rockchip_multicodecs.c @@ -740,6 +740,16 @@ static int rk_multicodecs_probe_keys(struct platform_device *pdev, return ret; } +static int rk_multicodecs_resume_post(struct snd_soc_card *card) +{ + struct multicodecs_data *mc_data = dev_get_drvdata(card->dev); + + if (gpiod_to_irq(mc_data->hp_det_gpio) >= 0) + queue_delayed_work(system_power_efficient_wq, &mc_data->handler, + msecs_to_jiffies(200)); + return 0; +} + static int rk_multicodecs_probe(struct platform_device *pdev) { struct snd_soc_card *card; @@ -917,6 +927,8 @@ static int rk_multicodecs_probe(struct platform_device *pdev) mc_data->hp_det_gpio = devm_gpiod_get_optional(&pdev->dev, "hp-det", GPIOD_IN); if (IS_ERR(mc_data->hp_det_gpio)) return PTR_ERR(mc_data->hp_det_gpio); + if (gpiod_to_irq(mc_data->hp_det_gpio) >= 0) + card->resume_post = &rk_multicodecs_resume_post; mc_data->extcon = devm_extcon_dev_allocate(&pdev->dev, headset_extcon_cable); if (IS_ERR(mc_data->extcon)) { From e1ecb83818326adbc29815f2a0f1fe590e70d00c Mon Sep 17 00:00:00 2001 From: Shunhua Lan Date: Thu, 28 Nov 2024 18:43:22 +0800 Subject: [PATCH 14/15] ASoC: rockchip: multicodecs: remove unused cables Signed-off-by: Shunhua Lan Change-Id: I66e1316e6c07fd13ce127c63d2f626803a96c6d1 --- sound/soc/rockchip/rockchip_multicodecs.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/sound/soc/rockchip/rockchip_multicodecs.c b/sound/soc/rockchip/rockchip_multicodecs.c index 04fc84311728..9d18fafea8e5 100644 --- a/sound/soc/rockchip/rockchip_multicodecs.c +++ b/sound/soc/rockchip/rockchip_multicodecs.c @@ -83,9 +83,9 @@ struct multicodecs_data { unsigned int rx_slot_mask; }; -static const unsigned int headset_extcon_cable[] = { - EXTCON_JACK_MICROPHONE, - EXTCON_JACK_HEADPHONE, +static unsigned int headset_extcon_cable[] = { + EXTCON_NONE, + EXTCON_NONE, EXTCON_NONE, }; @@ -762,6 +762,7 @@ static int rk_multicodecs_probe(struct platform_device *pdev) int count, irq; int ret = 0, i = 0, idx = 0; const char *prefix = "rockchip,"; + int cable = 0; ret = wait_locked_card(np, &pdev->dev); if (ret < 0) { @@ -908,6 +909,7 @@ static int rk_multicodecs_probe(struct platform_device *pdev) ret = rk_multicodecs_probe_keys(pdev, mc_data); if (ret) dev_warn(&pdev->dev, "Has no input keys\n"); + headset_extcon_cable[cable++] = EXTCON_JACK_MICROPHONE; } INIT_DEFERRABLE_WORK(&mc_data->handler, adc_jack_handler); @@ -927,8 +929,10 @@ static int rk_multicodecs_probe(struct platform_device *pdev) mc_data->hp_det_gpio = devm_gpiod_get_optional(&pdev->dev, "hp-det", GPIOD_IN); if (IS_ERR(mc_data->hp_det_gpio)) return PTR_ERR(mc_data->hp_det_gpio); - if (gpiod_to_irq(mc_data->hp_det_gpio) >= 0) + if (gpiod_to_irq(mc_data->hp_det_gpio) >= 0) { + headset_extcon_cable[cable++] = EXTCON_JACK_HEADPHONE; card->resume_post = &rk_multicodecs_resume_post; + } mc_data->extcon = devm_extcon_dev_allocate(&pdev->dev, headset_extcon_cable); if (IS_ERR(mc_data->extcon)) { From 0e6f34b90b7dee1271c4264b32668dbf7c198624 Mon Sep 17 00:00:00 2001 From: ChuanHu Sun Date: Wed, 3 Jul 2024 14:48:49 +0800 Subject: [PATCH 15/15] video: rockchip: mpp_osal: add api mpp_device_add_driver() for rockit Signed-off-by: ChuanHu Sun Change-Id: I2f945004f199b61935a4a1f5a49cf2d1c1ec093b --- drivers/video/rockchip/mpp_osal/mpp_osal.c | 13 +++++++++++++ drivers/video/rockchip/mpp_osal/mpp_osal.h | 1 + 2 files changed, 14 insertions(+) diff --git a/drivers/video/rockchip/mpp_osal/mpp_osal.c b/drivers/video/rockchip/mpp_osal/mpp_osal.c index 18f0185848ae..abdaf4be6a22 100644 --- a/drivers/video/rockchip/mpp_osal/mpp_osal.c +++ b/drivers/video/rockchip/mpp_osal/mpp_osal.c @@ -4,6 +4,7 @@ * */ #include "mpp_osal.h" +#include struct device_node *mpp_dev_of_node(struct device *dev) { @@ -28,3 +29,15 @@ int mpp_device_init_wakeup(struct device *dev, bool enable) return device_init_wakeup(dev, enable); } EXPORT_SYMBOL(mpp_device_init_wakeup); + +void mpp_device_add_driver(void *dev, void *drv) +{ +#ifdef CONFIG_PM_SLEEP + struct device *kdev = (struct device *)dev; + struct platform_driver *mpi_driver = (struct platform_driver *)drv; + + kdev->driver = &mpi_driver->driver; + kdev->power.no_pm_callbacks = 0; +#endif +} +EXPORT_SYMBOL(mpp_device_add_driver); diff --git a/drivers/video/rockchip/mpp_osal/mpp_osal.h b/drivers/video/rockchip/mpp_osal/mpp_osal.h index 733dd5a2bde6..826f006d8552 100644 --- a/drivers/video/rockchip/mpp_osal/mpp_osal.h +++ b/drivers/video/rockchip/mpp_osal/mpp_osal.h @@ -14,5 +14,6 @@ struct device_node *mpp_dev_of_node(struct device *dev); void mpp_pm_relax(struct device *dev); void mpp_pm_stay_awake(struct device *dev); int mpp_device_init_wakeup(struct device *dev, bool enable); +void mpp_device_add_driver(void *dev, void *drv); #endif