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 = ; 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; 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; +} 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)); } 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 diff --git a/drivers/ufs/host/ufs-rockchip.c b/drivers/ufs/host/ufs-rockchip.c index 53104cceb299..4b0fd9726522 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)) { @@ -441,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; 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 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; 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); 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) diff --git a/include/dt-bindings/suspend/rockchip-rk3588.h b/include/dt-bindings/suspend/rockchip-rk3588.h index 0dd63241c9a6..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) @@ -62,4 +63,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 diff --git a/sound/soc/rockchip/rockchip_multicodecs.c b/sound/soc/rockchip/rockchip_multicodecs.c index 9e346f105fae..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, }; @@ -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; @@ -752,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) { @@ -898,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); @@ -917,6 +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) { + 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)) {