diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig index 661127aed2f91..0b9c68547eab8 100644 --- a/drivers/iio/Kconfig +++ b/drivers/iio/Kconfig @@ -99,6 +99,7 @@ source "drivers/iio/humidity/Kconfig" source "drivers/iio/imu/Kconfig" source "drivers/iio/light/Kconfig" source "drivers/iio/magnetometer/Kconfig" +source "drivers/iio/motor/Kconfig" source "drivers/iio/multiplexer/Kconfig" source "drivers/iio/orientation/Kconfig" source "drivers/iio/test/Kconfig" diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile index cb80ef837e84f..e71fa60d8a8a6 100644 --- a/drivers/iio/Makefile +++ b/drivers/iio/Makefile @@ -35,6 +35,7 @@ obj-y += humidity/ obj-y += imu/ obj-y += light/ obj-y += magnetometer/ +obj-y += motor/ obj-y += multiplexer/ obj-y += orientation/ obj-y += position/ diff --git a/drivers/iio/motor/Kconfig b/drivers/iio/motor/Kconfig new file mode 100644 index 0000000000000..dac9b2a5c35d9 --- /dev/null +++ b/drivers/iio/motor/Kconfig @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Motor drivers and controllers +# +# When adding new entries keep the list in alphabetical order + +menu "Motor drivers and controllers" + +config TMC5271 + tristate "TMC5271 Stepper Driver and Controller" + depends on SPI + select REGMAP_SPI + help + Say yes here to enable support for the TMC5271 Stepper + Driver and Controller. +endmenu diff --git a/drivers/iio/motor/Makefile b/drivers/iio/motor/Makefile new file mode 100644 index 0000000000000..77dc2ae2410dc --- /dev/null +++ b/drivers/iio/motor/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Makefile for IIO Motor drivers and controllers support +# + +# When adding new entries keep the list in alphabetical order +obj-$(CONFIG_TMC5271) += tmc5271.o diff --git a/drivers/iio/motor/tmc5271.c b/drivers/iio/motor/tmc5271.c new file mode 100644 index 0000000000000..0590cc8b8c34f --- /dev/null +++ b/drivers/iio/motor/tmc5271.c @@ -0,0 +1,835 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * TMC5271 Stepper Driver and Controller + * + * Copyright (C) 2023 Analog Devices, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TMC5271_NAME "tmc5271" + +#define TMC5271_WRITE_BIT 0x80 +#define TMC5271_ADDRESS_MASK 0x7F + +#define TMC5271_REG_GCONF 0x00 +#define TMC5271_REG_GSTAT 0x01 +#define TMC5271_REG_IFCNT 0x02 +#define TMC5271_REG_SLAVECONF 0x03 +#define TMC5271_REG_IOIN 0x04 +#define TMC5271_REG_DRV_CONF 0x05 +#define TMC5271_REG_GLOBAL_SCALER 0x06 +#define TMC5271_REG_RAMPMODE 0x07 +#define TMC5271_REG_MSLUT_ADDR 0x08 +#define TMC5271_REG_MSLUT_DATA 0x09 +#define TMC5271_REG_X_COMPARE 0x10 +#define TMC5271_REG_X_COMPARE_REPEAT 0x11 +#define TMC5271_REG_IHOLD_IRUN 0x12 +#define TMC5271_REG_TPOWERDOWN 0x13 +#define TMC5271_REG_TSTEP 0x14 +#define TMC5271_REG_TPWMTHRS 0x15 +#define TMC5271_REG_TCOOLTHRS 0x16 +#define TMC5271_REG_THIGH 0x17 +#define TMC5271_REG_XACTUAL 0x18 +#define TMC5271_REG_VACTUAL 0x19 +#define TMC5271_REG_AACTUAL 0x1A +#define TMC5271_REG_VSTART 0x1B +#define TMC5271_REG_A1 0x1C +#define TMC5271_REG_V1 0x1D +#define TMC5271_REG_A2 0x1E +#define TMC5271_REG_V2 0x1F +#define TMC5271_REG_AMAX 0x20 +#define TMC5271_REG_VMAX 0x21 +#define TMC5271_REG_DMAX 0x22 +#define TMC5271_REG_D2 0x23 +#define TMC5271_REG_D1 0x24 +#define TMC5271_REG_VSTOP 0x25 +#define TMC5271_REG_TVMAX 0x26 +#define TMC5271_REG_TZEROWAIT 0x27 +#define TMC5271_REG_XTARGET 0x28 +#define TMC5271_REG_VDCMIN 0x29 +#define TMC5271_REG_SW_MODE 0x2A +#define TMC5271_REG_RAMP_STAT 0x2B +#define TMC5271_REG_XLATCH 0x2C +#define TMC5271_REG_POSITION_PI_CTRL 0x2D +#define TMC5271_REG_X_ENC 0x2E +#define TMC5271_REG_ENCMODE 0x2F +#define TMC5271_REG_ENC_CONST 0x30 +#define TMC5271_REG_ENC_STATUS 0x31 +#define TMC5271_REG_ENC_LATCH 0x32 +#define TMC5271_REG_ENC_DEVIATION 0x33 +#define TMC5271_REG_VIRTUAL_STOP_L 0x34 +#define TMC5271_REG_VIRTUAL_STOP_R 0x35 +#define TMC5271_REG_MSCNT 0x36 +#define TMC5271_REG_MSCURACT 0x37 +#define TMC5271_REG_CHOPCONF 0x38 +#define TMC5271_REG_COOLCONF 0x39 +#define TMC5271_REG_DCCTRL 0x3A +#define TMC5271_REG_DRV_STATUS 0x3B +#define TMC5271_REG_PWMCONF 0x3C +#define TMC5271_REG_PWM_SCALE 0x3D +#define TMC5271_REG_PWM_AUTO 0x3E +#define TMC5271_REG_SG4_THRS 0x3F +#define TMC5271_REG_SG4_RESULT 0x40 +#define TMC5271_REG_SG4_IND 0x41 + +#define TMC5271_EN_PWM_MODE_MASK 0x00000001 +#define TMC5271_EN_PWM_MODE_SHIFT 0 +#define TMC5271_MULTISTEP_FILT_MASK 0x00000002 +#define TMC5271_MULTISTEP_FILT_SHIFT 1 +#define TMC5271_SHAFT_MASK 0x00000004 +#define TMC5271_SHAFT_SHIFT 2 +#define TMC5271_DIAG0_ERROR_MASK 0x00000008 +#define TMC5271_DIAG0_ERROR_SHIFT 3 +#define TMC5271_DIAG0_OTPW_MASK 0x00000010 +#define TMC5271_DIAG0_OTPW_SHIFT 4 +#define TMC5271_DIAG0_STALL_STEP_MASK 0x00000020 +#define TMC5271_DIAG0_STALL_STEP_SHIFT 5 +#define TMC5271_DIAG1_STALL_DIR_MASK 0x00000040 +#define TMC5271_DIAG1_STALL_DIR_SHIFT 6 +#define TMC5271_DIAG1_INDEX_MASK 0x00000080 +#define TMC5271_DIAG1_INDEX_SHIFT 7 +#define TMC5271_DIAG0_INT_PUSHPULL_MASK 0x00000100 +#define TMC5271_DIAG0_INT_PUSHPULL_SHIFT 8 +#define TMC5271_DIAG1_POSCOMP_PUSHPULL_MASK 0x00000200 +#define TMC5271_DIAG1_POSCOMP_PUSHPULL_SHIFT 9 +#define TMC5271_SMALL_HYSTERESIS_MASK 0x00000400 +#define TMC5271_SMALL_HYSTERESIS_SHIFT 10 +#define TMC5271_STOP_ENABLE_MASK 0x00000800 +#define TMC5271_STOP_ENABLE_SHIFT 11 +#define TMC5271_DIRECT_MODE_MASK 0x00001000 +#define TMC5271_DIRECT_MODE_SHIFT 12 +#define TMC5271_SD_MASK 0x00002000 +#define TMC5271_SD_SHIFT 13 +#define TMC5271_DRV_ENN_MASK 0x00004000 +#define TMC5271_DRV_ENN_SHIFT 14 +#define TMC5271_QSC_STS_ENA_MASK 0x00008000 +#define TMC5271_QSC_STS_ENA_SHIFT 15 +#define TMC5271_DIAG0_SEL_NERROR_RAMP_MASK 0x20000000 +#define TMC5271_DIAG0_SEL_NERROR_RAMP_SHIFT 29 +#define TMC5271_RESET_MASK 0x00000001 +#define TMC5271_RESET_SHIFT 0 +#define TMC5271_DRV_ERR_MASK 0x00000002 +#define TMC5271_DRV_ERR_SHIFT 1 +#define TMC5271_UV_LDO_MASK 0x00000004 +#define TMC5271_UV_LDO_SHIFT 2 +#define TMC5271_REGISTER_RESET_MASK 0x00000008 +#define TMC5271_REGISTER_RESET_SHIFT 3 +#define TMC5271_VM_UVLO_MASK 0x00000010 +#define TMC5271_VM_UVLO_SHIFT 4 +#define TMC5271_IFCNT_MASK 0x000000FF +#define TMC5271_IFCNT_SHIFT 0 +#define TMC5271_SLAVEADDR_MASK 0x000000FF +#define TMC5271_SLAVEADDR_SHIFT 0 +#define TMC5271_SENDDELAY_MASK 0x00000F00 +#define TMC5271_SENDDELAY_SHIFT 8 +#define TMC5271_ADC_TEMPERATURE_MASK 0x000001FE +#define TMC5271_ADC_TEMPERATURE_SHIFT 1 +#define TMC5271_ADC_EN_MASK 0x00000200 +#define TMC5271_ADC_EN_SHIFT 9 +#define TMC5271_SEL_OSCILLATOR_MASK 0x00000800 +#define TMC5271_SEL_OSCILLATOR_SHIFT 11 +#define TMC5271_EXT_RES_DET_MASK 0x00001000 +#define TMC5271_EXT_RES_DET_SHIFT 12 +#define TMC5271_OUTPUT_MASK 0x00002000 +#define TMC5271_OUTPUT_SHIFT 13 +#define TMC5271_QSC_STATUS_MASK 0x00008000 +#define TMC5271_QSC_STATUS_SHIFT 15 +#define TMC5271_SILICON_RV_MASK 0x00070000 +#define TMC5271_SILICON_RV_SHIFT 16 +#define TMC5271_VERSION_MASK 0xFF000000 +#define TMC5271_VERSION_SHIFT 24 +#define TMC5271_FSR_MASK 0x00000003 +#define TMC5271_FSR_SHIFT 0 +#define TMC5271_FSR_IREF_MASK 0x0000000C +#define TMC5271_FSR_IREF_SHIFT 2 +#define TMC5271_EN_EMERGENCY_DISABLE_MASK 0x00000010 +#define TMC5271_EN_EMERGENCY_DISABLE_SHIFT 4 +#define TMC5271_STANDSTILL_TIME_MASK 0x00070000 +#define TMC5271_STANDSTILL_TIME_SHIFT 16 +#define TMC5271_GLOBALSCALER_A_MASK 0x000000FF +#define TMC5271_GLOBALSCALER_A_SHIFT 0 +#define TMC5271_GLOBALSCALER_B_MASK 0x0000FF00 +#define TMC5271_GLOBALSCALER_B_SHIFT 8 +#define TMC5271_RAMPMODE_MASK 0x00000003 +#define TMC5271_RAMPMODE_SHIFT 0 +#define TMC5271_MSLUT_ADDR_MASK 0x0000001F +#define TMC5271_MSLUT_ADDR_SHIFT 0 +#define TMC5271_MSLUT_DATA_MASK 0xFFFFFFFF +#define TMC5271_MSLUT_DATA_SHIFT 0 +#define TMC5271_X_COMPARE_MASK 0xFFFFFFFF +#define TMC5271_X_COMPARE_SHIFT 0 +#define TMC5271_X_COMPARE_REPEAT_MASK 0x00FFFFFF +#define TMC5271_X_COMPARE_REPEAT_SHIFT 0 +#define TMC5271_IHOLD_MASK 0x0000001F +#define TMC5271_IHOLD_SHIFT 0 +#define TMC5271_IRUN_MASK 0x00001F00 +#define TMC5271_IRUN_SHIFT 8 +#define TMC5271_IHOLDDELAY_MASK 0x000F0000 +#define TMC5271_IHOLDDELAY_SHIFT 16 +#define TMC5271_IRUNDELAY_MASK 0x0F000000 +#define TMC5271_IRUNDELAY_SHIFT 24 +#define TMC5271_TPOWERDOWN_MASK 0x000000FF +#define TMC5271_TPOWERDOWN_SHIFT 0 +#define TMC5271_TSTEP_MASK 0x000FFFFF +#define TMC5271_TSTEP_SHIFT 0 +#define TMC5271_TPWMTHRS_MASK 0x000FFFFF +#define TMC5271_TPWMTHRS_SHIFT 0 +#define TMC5271_TCOOLTHRS_MASK 0x000FFFFF +#define TMC5271_TCOOLTHRS_SHIFT 0 +#define TMC5271_THIGH_MASK 0x000FFFFF +#define TMC5271_THIGH_SHIFT 0 +#define TMC5271_XACTUAL_MASK 0xFFFFFFFF +#define TMC5271_XACTUAL_SHIFT 0 +#define TMC5271_VACTUAL_MASK 0x00FFFFFF +#define TMC5271_VACTUAL_SHIFT 0 +#define TMC5271_AACTUAL_MASK 0x00FFFFFF +#define TMC5271_AACTUAL_SHIFT 0 +#define TMC5271_VSTART_MASK 0x0003FFFF +#define TMC5271_VSTART_SHIFT 0 +#define TMC5271_A1_MASK 0x0003FFFF +#define TMC5271_A1_SHIFT 0 +#define TMC5271_V1_MASK 0x000FFFFF +#define TMC5271_V1_SHIFT 0 +#define TMC5271_A2_MASK 0x0003FFFF +#define TMC5271_A2_SHIFT 0 +#define TMC5271_V2_MASK 0x000FFFFF +#define TMC5271_V2_SHIFT 0 +#define TMC5271_AMAX_MASK 0x0003FFFF +#define TMC5271_AMAX_SHIFT 0 +#define TMC5271_VMAX_MASK 0x007FFFFF +#define TMC5271_VMAX_SHIFT 0 +#define TMC5271_DMAX_MASK 0x0003FFFF +#define TMC5271_DMAX_SHIFT 0 +#define TMC5271_D2_MASK 0x0003FFFF +#define TMC5271_D2_SHIFT 0 +#define TMC5271_D1_MASK 0x0003FFFF +#define TMC5271_D1_SHIFT 0 +#define TMC5271_VSTOP_MASK 0x0003FFFF +#define TMC5271_VSTOP_SHIFT 0 +#define TMC5271_TVMAX_MASK 0x0000FFFF +#define TMC5271_TVMAX_SHIFT 0 +#define TMC5271_TZEROWAIT_MASK 0x0000FFFF +#define TMC5271_TZEROWAIT_SHIFT 0 +#define TMC5271_XTARGET_MASK 0xFFFFFFFF +#define TMC5271_XTARGET_SHIFT 0 +#define TMC5271_VDCMIN_RESERVED_MASK 0x000000FF +#define TMC5271_VDCMIN_RESERVED_SHIFT 0 +#define TMC5271_VDCMIN_VDCMIN_MASK 0x007FFF00 +#define TMC5271_VDCMIN_VDCMIN_SHIFT 8 +#define TMC5271_SW_MODE_STOP_L_ENABLE_MASK 0x00000001 +#define TMC5271_SW_MODE_STOP_L_ENABLE_SHIFT 0 +#define TMC5271_SW_MODE_STOP_R_ENABLE_MASK 0x00000002 +#define TMC5271_SW_MODE_STOP_R_ENABLE_SHIFT 1 +#define TMC5271_SW_MODE_POL_STOP_L_MASK 0x00000004 +#define TMC5271_SW_MODE_POL_STOP_L_SHIFT 2 +#define TMC5271_SW_MODE_POL_STOP_R_MASK 0x00000008 +#define TMC5271_SW_MODE_POL_STOP_R_SHIFT 3 +#define TMC5271_SW_MODE_SWAP_LR_MASK 0x00000010 +#define TMC5271_SW_MODE_SWAP_LR_SHIFT 4 +#define TMC5271_SW_MODE_LATCH_L_ACTIVE_MASK 0x00000020 +#define TMC5271_SW_MODE_LATCH_L_ACTIVE_SHIFT 5 +#define TMC5271_SW_MODE_LATCH_L_INACTIVE_MASK 0x00000040 +#define TMC5271_SW_MODE_LATCH_L_INACTIVE_SHIFT 6 +#define TMC5271_SW_MODE_LATCH_R_ACTIVE_MASK 0x00000080 +#define TMC5271_SW_MODE_LATCH_R_ACTIVE_SHIFT 7 +#define TMC5271_SW_MODE_LATCH_R_INACTIVE_MASK 0x00000100 +#define TMC5271_SW_MODE_LATCH_R_INACTIVE_SHIFT 8 +#define TMC5271_SW_MODE_EN_LATCH_ENCODER_MASK 0x00000200 +#define TMC5271_SW_MODE_EN_LATCH_ENCODER_SHIFT 9 +#define TMC5271_SW_MODE_SG_STOP_MASK 0x00000400 +#define TMC5271_SW_MODE_SG_STOP_SHIFT 10 +#define TMC5271_SW_MODE_EN_SOFTSTOP_MASK 0x00000800 +#define TMC5271_SW_MODE_EN_SOFTSTOP_SHIFT 11 +#define TMC5271_SW_MODE_EN_VIRTUAL_STOP_L_MASK 0x00001000 +#define TMC5271_SW_MODE_EN_VIRTUAL_STOP_L_SHIFT 12 +#define TMC5271_SW_MODE_EN_VIRTUAL_STOP_R_MASK 0x00002000 +#define TMC5271_SW_MODE_EN_VIRTUAL_STOP_R_SHIFT 13 +#define TMC5271_SW_MODE_VIRTUAL_STEP_ENC_MASK 0x00004000 +#define TMC5271_SW_MODE_VIRTUAL_STEP_ENC_SHIFT 14 +#define TMC5271_STATUS_STOP_L_MASK 0x00000001 +#define TMC5271_STATUS_STOP_L_SHIFT 0 +#define TMC5271_STATUS_STOP_R_MASK 0x00000002 +#define TMC5271_STATUS_STOP_R_SHIFT 1 +#define TMC5271_STATUS_LATCH_L_MASK 0x00000004 +#define TMC5271_STATUS_LATCH_L_SHIFT 2 +#define TMC5271_STATUS_LATCH_R_MASK 0x00000008 +#define TMC5271_STATUS_LATCH_R_SHIFT 3 +#define TMC5271_EVENT_STOP_L_MASK 0x00000010 +#define TMC5271_EVENT_STOP_L_SHIFT 4 +#define TMC5271_EVENT_STOP_R_MASK 0x00000020 +#define TMC5271_EVENT_STOP_R_SHIFT 5 +#define TMC5271_EVENT_STOP_SG_MASK 0x00000040 +#define TMC5271_EVENT_STOP_SG_SHIFT 6 +#define TMC5271_EVENT_POS_REACHED_MASK 0x00000080 +#define TMC5271_EVENT_POS_REACHED_SHIFT 7 +#define TMC5271_VELOCITY_REACHED_MASK 0x00000100 +#define TMC5271_VELOCITY_REACHED_SHIFT 8 +#define TMC5271_POSITION_REACHED_MASK 0x00000200 +#define TMC5271_POSITION_REACHED_SHIFT 9 +#define TMC5271_VZERO_MASK 0x00000400 +#define TMC5271_VZERO_SHIFT 10 +#define TMC5271_T_ZEROWAIT_ACTIVE_MASK 0x00000800 +#define TMC5271_T_ZEROWAIT_ACTIVE_SHIFT 11 +#define TMC5271_SECOND_MOVE_MASK 0x00001000 +#define TMC5271_SECOND_MOVE_SHIFT 12 +#define TMC5271_STATUS_SG_MASK 0x00002000 +#define TMC5271_STATUS_SG_SHIFT 13 +#define TMC5271_STATUS_VIRTUAL_STOP_L_MASK 0x00004000 +#define TMC5271_STATUS_VIRTUAL_STOP_L_SHIFT 14 +#define TMC5271_STATUS_VIRTUAL_STOP_R_MASK 0x00008000 +#define TMC5271_STATUS_VIRTUAL_STOP_R_SHIFT 15 +#define TMC5271_XLATCH_MASK 0xFFFFFFFF +#define TMC5271_XLATCH_SHIFT 0 +#define TMC5271_P_POSITION_MASK 0x000003FF +#define TMC5271_P_POSITION_SHIFT 0 +#define TMC5271_TOLERANCE_MASK 0x00FF0000 +#define TMC5271_TOLERANCE_SHIFT 16 +#define TMC5271_TOL_ON_POS_REACHED_MASK 0x10000000 +#define TMC5271_TOL_ON_POS_REACHED_SHIFT 28 +#define TMC5271_X_ENC_MASK 0xFFFFFFFF +#define TMC5271_X_ENC_SHIFT 0 +#define TMC5271_POL_A_MASK 0x00000001 +#define TMC5271_POL_A_SHIFT 0 +#define TMC5271_POL_B_MASK 0x00000002 +#define TMC5271_POL_B_SHIFT 1 +#define TMC5271_POL_N_MASK 0x00000004 +#define TMC5271_POL_N_SHIFT 2 +#define TMC5271_IGNORE_AB_MASK 0x00000008 +#define TMC5271_IGNORE_AB_SHIFT 3 +#define TMC5271_CLR_CONT_MASK 0x00000010 +#define TMC5271_CLR_CONT_SHIFT 4 +#define TMC5271_CLR_ONCE_MASK 0x00000020 +#define TMC5271_CLR_ONCE_SHIFT 5 +#define TMC5271_POS_NEG_EDGE_MASK 0x000000C0 +#define TMC5271_POS_NEG_EDGE_SHIFT 6 +#define TMC5271_CLR_ENC_X_MASK 0x00000100 +#define TMC5271_CLR_ENC_X_SHIFT 8 +#define TMC5271_LATCH_X_ACT_MASK 0x00000200 +#define TMC5271_LATCH_X_ACT_SHIFT 9 +#define TMC5271_ENC_SEL_DECIMAL_MASK 0x00000400 +#define TMC5271_ENC_SEL_DECIMAL_SHIFT 10 +#define TMC5271_NBEMF_ABN_SEL_MASK 0x00000800 +#define TMC5271_NBEMF_ABN_SEL_SHIFT 11 +#define TMC5271_BEMF_HYST_MASK 0x00007000 +#define TMC5271_BEMF_HYST_SHIFT 12 +#define TMC5271_QSC_ENC_EN_MASK 0x00008000 +#define TMC5271_QSC_ENC_EN_SHIFT 15 +#define TMC5271_BEMF_BLANK_TIME_MASK 0x00FF0000 +#define TMC5271_BEMF_BLANK_TIME_SHIFT 16 +#define TMC5271_BEMF_FILTER_SEL_MASK 0x30000000 +#define TMC5271_BEMF_FILTER_SEL_SHIFT 28 +#define TMC5271_ENC_CONST_MASK 0xFFFFFFFF +#define TMC5271_ENC_CONST_SHIFT 0 +#define TMC5271_N_EVENT_MASK 0x00000001 +#define TMC5271_N_EVENT_SHIFT 0 +#define TMC5271_DEVIATION_WARN_MASK 0x00000002 +#define TMC5271_DEVIATION_WARN_SHIFT 1 +#define TMC5271_ENC_LATCH_MASK 0xFFFFFFFF +#define TMC5271_ENC_LATCH_SHIFT 0 +#define TMC5271_ENC_DEVIATION_MASK 0x000FFFFF +#define TMC5271_ENC_DEVIATION_SHIFT 0 +#define TMC5271_VIRTUAL_STOP_L_MASK 0xFFFFFFFF +#define TMC5271_VIRTUAL_STOP_L_SHIFT 0 +#define TMC5271_VIRTUAL_STOP_R_MASK 0xFFFFFFFF +#define TMC5271_VIRTUAL_STOP_R_SHIFT 0 +#define TMC5271_MSCNT_MASK 0x000003FF +#define TMC5271_MSCNT_SHIFT 0 +#define TMC5271_CUR_A_MASK 0x000001FF +#define TMC5271_CUR_A_SHIFT 0 +#define TMC5271_CUR_B_MASK 0x01FF0000 +#define TMC5271_CUR_B_SHIFT 16 +#define TMC5271_TOFF_MASK 0x0000000F +#define TMC5271_TOFF_SHIFT 0 +#define TMC5271_HSTRT_TFD210_MASK 0x00000070 +#define TMC5271_HSTRT_TFD210_SHIFT 4 +#define TMC5271_HEND_OFFSET_MASK 0x00000780 +#define TMC5271_HEND_OFFSET_SHIFT 7 +#define TMC5271_FD3_MASK 0x00000800 +#define TMC5271_FD3_SHIFT 11 +#define TMC5271_DISFDCC_MASK 0x00001000 +#define TMC5271_DISFDCC_SHIFT 12 +#define TMC5271_CHM_MASK 0x00004000 +#define TMC5271_CHM_SHIFT 14 +#define TMC5271_TBL_MASK 0x00018000 +#define TMC5271_TBL_SHIFT 15 +#define TMC5271_VHIGHFS_MASK 0x00040000 +#define TMC5271_VHIGHFS_SHIFT 18 +#define TMC5271_VHIGHCHM_MASK 0x00080000 +#define TMC5271_VHIGHCHM_SHIFT 19 +#define TMC5271_TPFD_MASK 0x00F00000 +#define TMC5271_TPFD_SHIFT 20 +#define TMC5271_MRES_MASK 0x0F000000 +#define TMC5271_MRES_SHIFT 24 +#define TMC5271_INTPOL_MASK 0x10000000 +#define TMC5271_INTPOL_SHIFT 28 +#define TMC5271_DEDGE_MASK 0x20000000 +#define TMC5271_DEDGE_SHIFT 29 +#define TMC5271_DISS2G_MASK 0x40000000 +#define TMC5271_DISS2G_SHIFT 30 +#define TMC5271_DISS2VS_MASK 0x80000000 +#define TMC5271_DISS2VS_SHIFT 31 +#define TMC5271_SEMIN_MASK 0x0000000F +#define TMC5271_SEMIN_SHIFT 0 +#define TMC5271_SEUP_MASK 0x00000060 +#define TMC5271_SEUP_SHIFT 5 +#define TMC5271_SEMAX_MASK 0x00000F00 +#define TMC5271_SEMAX_SHIFT 8 +#define TMC5271_SEDN_MASK 0x00006000 +#define TMC5271_SEDN_SHIFT 13 +#define TMC5271_SEIMIN_MASK 0x00008000 +#define TMC5271_SEIMIN_SHIFT 15 +#define TMC5271_SGT_MASK 0x007F0000 +#define TMC5271_SGT_SHIFT 16 +#define TMC5271_SFILT_MASK 0x01000000 +#define TMC5271_SFILT_SHIFT 24 +#define TMC5271_DC_TIME_MASK 0x000003FF +#define TMC5271_DC_TIME_SHIFT 0 +#define TMC5271_DC_SG_MASK 0x00FF0000 +#define TMC5271_DC_SG_SHIFT 16 +#define TMC5271_SG_RESULT_MASK 0x000003FF +#define TMC5271_SG_RESULT_SHIFT 0 +#define TMC5271_S2VSA_MASK 0x00001000 +#define TMC5271_S2VSA_SHIFT 12 +#define TMC5271_S2VSB_MASK 0x00002000 +#define TMC5271_S2VSB_SHIFT 13 +#define TMC5271_STEALTH_MASK 0x00004000 +#define TMC5271_STEALTH_SHIFT 14 +#define TMC5271_FSACTIVE_MASK 0x00008000 +#define TMC5271_FSACTIVE_SHIFT 15 +#define TMC5271_CS_ACTUAL_MASK 0x001F0000 +#define TMC5271_CS_ACTUAL_SHIFT 16 +#define TMC5271_STALLGUARD_MASK 0x01000000 +#define TMC5271_STALLGUARD_SHIFT 24 +#define TMC5271_OT_MASK 0x02000000 +#define TMC5271_OT_SHIFT 25 +#define TMC5271_OTPW_MASK 0x04000000 +#define TMC5271_OTPW_SHIFT 26 +#define TMC5271_S2GA_MASK 0x08000000 +#define TMC5271_S2GA_SHIFT 27 +#define TMC5271_S2GB_MASK 0x10000000 +#define TMC5271_S2GB_SHIFT 28 +#define TMC5271_OLA_MASK 0x20000000 +#define TMC5271_OLA_SHIFT 29 +#define TMC5271_OLB_MASK 0x40000000 +#define TMC5271_OLB_SHIFT 30 +#define TMC5271_STST_MASK 0x80000000 +#define TMC5271_STST_SHIFT 31 +#define TMC5271_PWM_OFS_MASK 0x000000FF +#define TMC5271_PWM_OFS_SHIFT 0 +#define TMC5271_PWM_GRAD_MASK 0x0000FF00 +#define TMC5271_PWM_GRAD_SHIFT 8 +#define TMC5271_PWM_FREQ_MASK 0x00030000 +#define TMC5271_PWM_FREQ_SHIFT 16 +#define TMC5271_PWM_AUTOSCALE_MASK 0x00040000 +#define TMC5271_PWM_AUTOSCALE_SHIFT 18 +#define TMC5271_PWM_AUTOGRAD_MASK 0x00080000 +#define TMC5271_PWM_AUTOGRAD_SHIFT 19 +#define TMC5271_FREEWHEEL_MASK 0x00300000 +#define TMC5271_FREEWHEEL_SHIFT 20 +#define TMC5271_PWM_MEAS_SD_ENABLE_MASK 0x00400000 +#define TMC5271_PWM_MEAS_SD_ENABLE_SHIFT 22 +#define TMC5271_PWM_DIS_REG_STST_MASK 0x00800000 +#define TMC5271_PWM_DIS_REG_STST_SHIFT 23 +#define TMC5271_PWM_REG_MASK 0x0F000000 +#define TMC5271_PWM_REG_SHIFT 24 +#define TMC5271_PWM_LIM_MASK 0xF0000000 +#define TMC5271_PWM_LIM_SHIFT 28 +#define TMC5271_PWM_SCALE_SUM_MASK 0x000003FF +#define TMC5271_PWM_SCALE_SUM_SHIFT 0 +#define TMC5271_PWM_SCALE_AUTO_MASK 0x01FF0000 +#define TMC5271_PWM_SCALE_AUTO_SHIFT 16 +#define TMC5271_PWM_OFS_AUTO_MASK 0x000000FF +#define TMC5271_PWM_OFS_AUTO_SHIFT 0 +#define TMC5271_PWM_GRAD_AUTO_MASK 0x00FF0000 +#define TMC5271_PWM_GRAD_AUTO_SHIFT 16 +#define TMC5271_SG4_THRS_MASK 0x000000FF +#define TMC5271_SG4_THRS_SHIFT 0 +#define TMC5271_SG4_FILT_EN_MASK 0x00000100 +#define TMC5271_SG4_FILT_EN_SHIFT 8 +#define TMC5271_SG_ANGLE_OFFSET_MASK 0x00000200 +#define TMC5271_SG_ANGLE_OFFSET_SHIFT 9 +#define TMC5271_SG4_RESULT_SG_RESULT_MASK 0x000003FF +#define TMC5271_SG4_RESULT_SG_RESULT_SHIFT 0 +#define TMC5271_IND_0_MASK 0x000000FF +#define TMC5271_IND_0_SHIFT 0 +#define TMC5271_IND_1_MASK 0x0000FF00 +#define TMC5271_IND_1_SHIFT 8 +#define TMC5271_IND_2_MASK 0x00FF0000 +#define TMC5271_IND_2_SHIFT 16 +#define TMC5271_IND_3_MASK 0xFF000000 +#define TMC5271_IND_3_SHIFT 24 + +#define TMC5271_MODE_POSITION 0 +#define TMC5271_MODE_VELPOS 1 +#define TMC5271_MODE_VELNEG 2 +#define TMC5271_MODE_HOLD 3 + +struct tmc5271_priv { + struct spi_device *spi; + struct gpio_desc *gpio_sleep; + bool enable; + s32 velocity; + u32 acceleration; + bool irq_flag; +}; + +static int tmc5271_reg_read(struct spi_device *spi, + u8 reg_addr, + u32 *reg_data) +{ + u8 tx[5]; + u8 rx[5]; + struct spi_transfer t = { + .tx_buf = tx, + .rx_buf = rx, + .len = 5, + }; + int ret; + + tx[0] = 0x00 | (reg_addr & TMC5271_ADDRESS_MASK); + tx[1] = 0x00; + tx[2] = 0x00; + tx[3] = 0x00; + tx[4] = 0x00; + + ret = spi_sync_transfer(spi, &t, 1); + + tx[0] = 0x00 | (reg_addr & TMC5271_ADDRESS_MASK); + tx[1] = 0x00; + tx[2] = 0x00; + tx[3] = 0x00; + tx[4] = 0x00; + + ret |= spi_sync_transfer(spi, &t, 1); + + *reg_data = (rx[1] << 24) | (rx[2] << 16) | + (rx[3] << 8) | (rx[4] << 0); + + return ret; +} + +static int tmc5271_reg_write(struct spi_device *spi, + u8 reg_addr, + u32 reg_data) +{ + u8 tx[5]; + u8 rx[5]; + struct spi_transfer t = { + .tx_buf = tx, + .rx_buf = rx, + .len = 5, + }; + int ret; + + tx[0] = TMC5271_WRITE_BIT | (reg_addr & TMC5271_ADDRESS_MASK); + tx[1] = (reg_data & 0xff000000) >> 24; + tx[2] = (reg_data & 0x00ff0000) >> 16; + tx[3] = (reg_data & 0x0000ff00) >> 8; + tx[4] = (reg_data & 0x000000ff) >> 0; + + ret = spi_sync_transfer(spi, &t, 1); + + return ret; +} + +static int tmc5271_reg_write_mask(struct spi_device *spi, + u8 reg_addr, + u32 mask, + u8 shift, + u32 data) +{ + u32 reg_data; + int ret; + + ret = tmc5271_reg_read(spi, reg_addr, ®_data); + reg_data &= ~mask; + reg_data |= (data << shift); + ret |= tmc5271_reg_write(spi, reg_addr, reg_data); + + return ret; +} + +static irqreturn_t tmc5271_interrupt(int irq, void *dev_id) +{ + struct iio_dev *indio_dev = dev_id; + struct tmc5271_priv *priv = iio_priv(indio_dev); + + priv->irq_flag = true; + + return IRQ_HANDLED; + +}; + +static int tmc5271_rotate(struct iio_dev *indio_dev, s32 velocity) +{ + struct tmc5271_priv *priv = iio_priv(indio_dev); + int ret; + + ret = tmc5271_reg_write(priv->spi, TMC5271_REG_VMAX, + abs(velocity)); + ret |= tmc5271_reg_write_mask(priv->spi, TMC5271_REG_RAMPMODE, + TMC5271_RAMPMODE_MASK, TMC5271_RAMPMODE_SHIFT, + (velocity >= 0) ? TMC5271_MODE_VELPOS : TMC5271_MODE_VELNEG); + + return ret; +} + +static int tmc5271_en_driver(struct iio_dev *indio_dev, bool en) +{ + struct tmc5271_priv *priv = iio_priv(indio_dev); + int ret; + priv->irq_flag = false; + + if (en) { + gpiod_set_value_cansleep(priv->gpio_sleep, 0); + mdelay(1); + + ret |= tmc5271_reg_write_mask(priv->spi, TMC5271_REG_GCONF, + TMC5271_QSC_STS_ENA_MASK, + TMC5271_QSC_STS_ENA_SHIFT, 0); + ret |= tmc5271_reg_write_mask(priv->spi, TMC5271_REG_IOIN, + TMC5271_ADC_EN_MASK, + TMC5271_ADC_EN_SHIFT, 1); + ret |= tmc5271_reg_write_mask(priv->spi, TMC5271_REG_ENCMODE, + TMC5271_QSC_ENC_EN_MASK, + TMC5271_QSC_ENC_EN_SHIFT, 1); + ret |= tmc5271_reg_write_mask(priv->spi, TMC5271_REG_PWMCONF, + TMC5271_FREEWHEEL_MASK, + TMC5271_FREEWHEEL_SHIFT, 0); + ret |= tmc5271_reg_write_mask(priv->spi, TMC5271_REG_GCONF, + TMC5271_DRV_ENN_MASK, + TMC5271_DRV_ENN_SHIFT, 0); + ret |= tmc5271_reg_write_mask(priv->spi, TMC5271_REG_CHOPCONF, + TMC5271_TOFF_MASK, + TMC5271_TOFF_SHIFT, 3); + ret |= tmc5271_reg_write(priv->spi, TMC5271_REG_AMAX, + priv->acceleration); + + return ret |= tmc5271_rotate(indio_dev, priv->velocity); + + } else { + enable_irq(priv->spi->irq); + + gpiod_set_value_cansleep(priv->gpio_sleep, 1); + mdelay(1); + + ret |= tmc5271_reg_write_mask(priv->spi, TMC5271_REG_GCONF, + TMC5271_DRV_ENN_MASK, + TMC5271_DRV_ENN_SHIFT, 1); + + if (priv->irq_flag) { + int event_pos_reached; + ret |= tmc5271_reg_read(priv->spi, + TMC5271_REG_RAMP_STAT, + &event_pos_reached); + event_pos_reached = + event_pos_reached & + TMC5271_EVENT_POS_REACHED_MASK >> + TMC5271_EVENT_POS_REACHED_SHIFT; + + if (event_pos_reached) { + ret |= tmc5271_reg_write_mask( + priv->spi, TMC5271_REG_RAMP_STAT, + TMC5271_EVENT_POS_REACHED_MASK, + TMC5271_EVENT_POS_REACHED_SHIFT, 1); + } + } + + ret |= tmc5271_reg_write_mask(priv->spi, TMC5271_REG_GCONF, + TMC5271_QSC_STS_ENA_MASK, + TMC5271_QSC_STS_ENA_SHIFT, 1); + ret |= tmc5271_reg_write_mask(priv->spi, TMC5271_REG_IOIN, + TMC5271_ADC_EN_MASK, + TMC5271_ADC_EN_SHIFT, 0); + ret |= tmc5271_reg_write_mask(priv->spi, TMC5271_REG_ENCMODE, + TMC5271_QSC_ENC_EN_MASK, + TMC5271_QSC_ENC_EN_SHIFT, 1); + ret |= tmc5271_reg_write_mask(priv->spi, TMC5271_REG_PWMCONF, + TMC5271_FREEWHEEL_MASK, + TMC5271_FREEWHEEL_SHIFT, 1); + + disable_irq(priv->spi->irq); + } + + return ret; +} + +static int tmc5271_setup(struct iio_dev *indio_dev) +{ + struct tmc5271_priv *priv = iio_priv(indio_dev); + int ret; + + ret = tmc5271_en_driver(indio_dev, + priv->enable); + ret |= tmc5271_reg_write_mask(priv->spi, TMC5271_REG_CHOPCONF, + TMC5271_TOFF_MASK, TMC5271_TOFF_SHIFT, 3); + + ret |= tmc5271_reg_write(priv->spi, TMC5271_REG_AMAX, + priv->acceleration); + ret |= tmc5271_rotate(indio_dev, + priv->velocity); + + return ret; +} + +static int tmc5271_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, + int *val2, + long mask) +{ + struct tmc5271_priv *priv = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_ENABLE: + *val = priv->enable; + return IIO_VAL_INT; + case IIO_CHAN_INFO_RAW: + if (chan->type == IIO_VELOCITY) + *val = priv->velocity; + if (chan->type == IIO_ACCEL) + *val = priv->acceleration; + return IIO_VAL_INT; + } + + return -EINVAL; +} + +static int tmc5271_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, + int val2, + long mask) +{ + struct tmc5271_priv *priv = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_ENABLE: + priv->enable = val; + return tmc5271_en_driver(indio_dev, priv->enable); + case IIO_CHAN_INFO_RAW: + if (chan->type == IIO_VELOCITY) { + priv->velocity = val; + return tmc5271_rotate(indio_dev, priv->velocity); + } + if (chan->type == IIO_ACCEL) { + priv->acceleration = val; + return tmc5271_reg_write(priv->spi, TMC5271_REG_AMAX, + priv->acceleration); + } + } + + return -EINVAL; +} + +static int tmc5271_reg_access(struct iio_dev *indio_dev, + unsigned reg, unsigned writeval, + unsigned *readval) +{ + struct tmc5271_priv *priv = iio_priv(indio_dev); + + if (readval) + return tmc5271_reg_read(priv->spi, reg, readval); + + return tmc5271_reg_write(priv->spi, reg, writeval); +} + +static const struct iio_info tmc5271_info = { + .read_raw = &tmc5271_read_raw, + .write_raw = &tmc5271_write_raw, + .debugfs_reg_access = &tmc5271_reg_access, +}; + +static const struct iio_chan_spec tmc5271_channels[] = { + { + .type = IIO_VELOCITY, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_ENABLE), + .output = 1, + .channel = 0, + }, { + .type = IIO_ACCEL, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_ENABLE), + .output = 1, + .channel = 1, + } +}; + +static int tmc5271_probe(struct spi_device *spi) +{ + struct iio_dev *indio_dev; + struct tmc5271_priv *priv; + int ret; + + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*priv)); + if (!indio_dev) + return -ENOMEM; + + priv = iio_priv(indio_dev); + + priv->gpio_sleep = devm_gpiod_get_optional(&spi->dev, "sleep", + GPIOD_OUT_LOW); + if (IS_ERR(priv->gpio_sleep)) + return PTR_ERR(priv->gpio_sleep); + + if (priv->gpio_sleep) { + gpiod_set_value_cansleep(priv->gpio_sleep, 1); + mdelay(1); + gpiod_set_value_cansleep(priv->gpio_sleep, 0); + mdelay(1); + } + + priv->spi = spi; + priv->enable = true; + priv->velocity = 50000; + priv->acceleration = 100; + + ret = tmc5271_setup(indio_dev); + if (ret) + return ret; + + indio_dev->name = TMC5271_NAME; + indio_dev->channels = tmc5271_channels; + indio_dev->num_channels = ARRAY_SIZE(tmc5271_channels); + indio_dev->info = &tmc5271_info; + + ret = request_irq(priv->spi->irq, + &tmc5271_interrupt, + IRQF_TRIGGER_FALLING, + "qsc_rdy", indio_dev); + if (ret) + return ret; + + return devm_iio_device_register(&spi->dev, indio_dev); +} + +static const struct of_device_id tmc5271_of_match[] = { + { + .compatible = "adi,tmc5271", + }, + { } +}; +MODULE_DEVICE_TABLE(of, tmc5271_of_match); + +static struct spi_driver tmc5271_driver = { + .driver = { + .name = TMC5271_NAME, + .of_match_table = tmc5271_of_match, + }, + .probe = tmc5271_probe, +}; +module_spi_driver(tmc5271_driver); + +MODULE_AUTHOR("Dragos Bogdan "); +MODULE_DESCRIPTION("TMC5271 Driver"); +MODULE_LICENSE("GPL v2");