Commit e86df907 authored by Xinpeng Sun's avatar Xinpeng Sun Committed by Jiri Kosina
Browse files

HID: intel-thc-hid: intel-thc: Add THC LTR interfaces



THC supports LTR configuration and runtimely mode switching. There
are two LTR modes: Active LTR and Low Power LTR.

THC hardware layer provides APIs for LTR configuration and mode
switching.

Co-developed-by: default avatarEven Xu <even.xu@intel.com>
Signed-off-by: default avatarEven Xu <even.xu@intel.com>
Signed-off-by: default avatarXinpeng Sun <xinpeng.sun@intel.com>
Tested-by: default avatarRui Zhang <rui1.zhang@intel.com>
Tested-by: default avatarMark Pearson <mpearson-lenovo@squebb.ca>
Reviewed-by: default avatarSrinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Reviewed-by: default avatarMark Pearson <mpearson-lenovo@squebb.ca>
Tested-by: default avatarAaron Ma <aaron.ma@canonical.com>
Signed-off-by: default avatarJiri Kosina <jkosina@suse.com>
parent a688404b
Loading
Loading
Loading
Loading
+114 −0
Original line number Diff line number Diff line
@@ -688,6 +688,120 @@ void thc_set_pio_interrupt_support(struct thc_device *dev, bool supported)
}
EXPORT_SYMBOL_NS_GPL(thc_set_pio_interrupt_support, "INTEL_THC");

/**
 * thc_ltr_config - Configure THC Latency Tolerance Reporting(LTR) settings
 *
 * @dev: The pointer of THC private device context
 * @active_ltr_us: active LTR value, unit is us
 * @lp_ltr_us: low power LTR value, unit is us
 */
void thc_ltr_config(struct thc_device *dev, u32 active_ltr_us, u32 lp_ltr_us)
{
	u32 active_ltr_scale, lp_ltr_scale, ltr_ctrl, ltr_mask, orig, tmp;

	if (active_ltr_us >= THC_LTR_MIN_VAL_SCALE_3 &&
	    active_ltr_us < THC_LTR_MAX_VAL_SCALE_3) {
		active_ltr_scale = THC_LTR_SCALE_3;
		active_ltr_us = active_ltr_us >> 5;
	} else if (active_ltr_us >= THC_LTR_MIN_VAL_SCALE_4 &&
		   active_ltr_us < THC_LTR_MAX_VAL_SCALE_4) {
		active_ltr_scale = THC_LTR_SCALE_4;
		active_ltr_us = active_ltr_us >> 10;
	} else if (active_ltr_us >= THC_LTR_MIN_VAL_SCALE_5 &&
		   active_ltr_us < THC_LTR_MAX_VAL_SCALE_5) {
		active_ltr_scale = THC_LTR_SCALE_5;
		active_ltr_us = active_ltr_us >> 15;
	} else {
		active_ltr_scale = THC_LTR_SCALE_2;
	}

	if (lp_ltr_us >= THC_LTR_MIN_VAL_SCALE_3 &&
	    lp_ltr_us < THC_LTR_MAX_VAL_SCALE_3) {
		lp_ltr_scale = THC_LTR_SCALE_3;
		lp_ltr_us = lp_ltr_us >> 5;
	} else if (lp_ltr_us >= THC_LTR_MIN_VAL_SCALE_4 &&
		   lp_ltr_us < THC_LTR_MAX_VAL_SCALE_4) {
		lp_ltr_scale = THC_LTR_SCALE_4;
		lp_ltr_us = lp_ltr_us >> 10;
	} else if (lp_ltr_us >= THC_LTR_MIN_VAL_SCALE_5 &&
		   lp_ltr_us < THC_LTR_MAX_VAL_SCALE_5) {
		lp_ltr_scale = THC_LTR_SCALE_5;
		lp_ltr_us = lp_ltr_us >> 15;
	} else {
		lp_ltr_scale = THC_LTR_SCALE_2;
	}

	regmap_read(dev->thc_regmap, THC_M_CMN_LTR_CTRL_OFFSET, &orig);
	ltr_ctrl = FIELD_PREP(THC_M_CMN_LTR_CTRL_ACT_LTR_VAL, active_ltr_us) |
		   FIELD_PREP(THC_M_CMN_LTR_CTRL_ACT_LTR_SCALE, active_ltr_scale) |
		   THC_M_CMN_LTR_CTRL_ACTIVE_LTR_REQ |
		   THC_M_CMN_LTR_CTRL_ACTIVE_LTR_EN |
		   FIELD_PREP(THC_M_CMN_LTR_CTRL_LP_LTR_VAL, lp_ltr_us) |
		   FIELD_PREP(THC_M_CMN_LTR_CTRL_LP_LTR_SCALE, lp_ltr_scale) |
		   THC_M_CMN_LTR_CTRL_LP_LTR_REQ;

	ltr_mask = THC_M_CMN_LTR_CTRL_ACT_LTR_VAL |
		   THC_M_CMN_LTR_CTRL_ACT_LTR_SCALE |
		   THC_M_CMN_LTR_CTRL_ACTIVE_LTR_REQ |
		   THC_M_CMN_LTR_CTRL_ACTIVE_LTR_EN |
		   THC_M_CMN_LTR_CTRL_LP_LTR_VAL |
		   THC_M_CMN_LTR_CTRL_LP_LTR_SCALE |
		   THC_M_CMN_LTR_CTRL_LP_LTR_REQ |
		   THC_M_CMN_LTR_CTRL_LP_LTR_EN;

	tmp = orig & ~ltr_mask;
	tmp |= ltr_ctrl & ltr_mask;

	regmap_write(dev->thc_regmap, THC_M_CMN_LTR_CTRL_OFFSET, tmp);
}
EXPORT_SYMBOL_NS_GPL(thc_ltr_config, "INTEL_THC");

/**
 * thc_change_ltr_mode - Change THC LTR mode
 *
 * @dev: The pointer of THC private device context
 * @ltr_mode: LTR mode(active or low power)
 */
void thc_change_ltr_mode(struct thc_device *dev, u32 ltr_mode)
{
	if (ltr_mode == THC_LTR_MODE_ACTIVE) {
		regmap_write_bits(dev->thc_regmap, THC_M_CMN_LTR_CTRL_OFFSET,
				  THC_M_CMN_LTR_CTRL_LP_LTR_EN, 0);
		regmap_write_bits(dev->thc_regmap, THC_M_CMN_LTR_CTRL_OFFSET,
				  THC_M_CMN_LTR_CTRL_ACTIVE_LTR_EN,
				  THC_M_CMN_LTR_CTRL_ACTIVE_LTR_EN);
		return;
	}

	regmap_write_bits(dev->thc_regmap, THC_M_CMN_LTR_CTRL_OFFSET,
			  THC_M_CMN_LTR_CTRL_ACTIVE_LTR_EN, 0);
	regmap_write_bits(dev->thc_regmap, THC_M_CMN_LTR_CTRL_OFFSET,
			  THC_M_CMN_LTR_CTRL_LP_LTR_EN,
			  THC_M_CMN_LTR_CTRL_LP_LTR_EN);
}
EXPORT_SYMBOL_NS_GPL(thc_change_ltr_mode, "INTEL_THC");

/**
 * thc_ltr_unconfig - Unconfigure THC Latency Tolerance Reporting(LTR) settings
 *
 * @dev: The pointer of THC private device context
 */
void thc_ltr_unconfig(struct thc_device *dev)
{
	u32 ltr_ctrl, bits_clear;

	regmap_read(dev->thc_regmap, THC_M_CMN_LTR_CTRL_OFFSET, &ltr_ctrl);
	bits_clear = THC_M_CMN_LTR_CTRL_LP_LTR_EN |
			THC_M_CMN_LTR_CTRL_ACTIVE_LTR_EN |
			THC_M_CMN_LTR_CTRL_LP_LTR_REQ |
			THC_M_CMN_LTR_CTRL_ACTIVE_LTR_REQ;

	ltr_ctrl &= ~bits_clear;

	regmap_write(dev->thc_regmap, THC_M_CMN_LTR_CTRL_OFFSET, ltr_ctrl);
}
EXPORT_SYMBOL_NS_GPL(thc_ltr_unconfig, "INTEL_THC");

MODULE_AUTHOR("Xinpeng Sun <xinpeng.sun@intel.com>");
MODULE_AUTHOR("Even Xu <even.xu@intel.com>");

+3 −0
Original line number Diff line number Diff line
@@ -68,5 +68,8 @@ void thc_int_trigger_type_select(struct thc_device *dev, bool edge_trigger);
void thc_interrupt_enable(struct thc_device *dev, bool int_enable);
void thc_set_pio_interrupt_support(struct thc_device *dev, bool supported);
int thc_interrupt_quiesce(const struct thc_device *dev, bool int_quiesce);
void thc_ltr_config(struct thc_device *dev, u32 active_ltr_us, u32 lp_ltr_us);
void thc_change_ltr_mode(struct thc_device *dev, u32 ltr_mode);
void thc_ltr_unconfig(struct thc_device *dev);

#endif /* _INTEL_THC_DEV_H_ */
+21 −0
Original line number Diff line number Diff line
@@ -656,6 +656,27 @@
/* Interrupt Quiesce default timeout value */
#define THC_QUIESCE_EN_TIMEOUT_US		USEC_PER_SEC /* 1s */

/* LTR definition */
/*
 * THC uses scale to calculate final LTR value.
 * Scale is geometric progression of 2^5 step, starting from 2^0.
 * For example, THC_LTR_SCALE_2(2) means 2^(5 * 2) = 1024, unit is ns.
 */
#define THC_LTR_SCALE_0				0
#define THC_LTR_SCALE_1				1
#define THC_LTR_SCALE_2				2
#define THC_LTR_SCALE_3				3
#define THC_LTR_SCALE_4				4
#define THC_LTR_SCALE_5				5
#define THC_LTR_MODE_ACTIVE			0
#define THC_LTR_MODE_LP				1
#define THC_LTR_MIN_VAL_SCALE_3			BIT(10)
#define THC_LTR_MAX_VAL_SCALE_3			BIT(15)
#define THC_LTR_MIN_VAL_SCALE_4			BIT(15)
#define THC_LTR_MAX_VAL_SCALE_4			BIT(20)
#define THC_LTR_MIN_VAL_SCALE_5			BIT(20)
#define THC_LTR_MAX_VAL_SCALE_5			BIT(25)

/*
 * THC PIO opcode default value
 * @THC_PIO_OP_SPI_TIC_READ: THC opcode for SPI PIO read