Commit 992bbc9e authored by Jeff LaBundy's avatar Jeff LaBundy Committed by Dmitry Torokhov
Browse files

Input: iqs269a - add support for OTP variants



This patch adds support for each available OTP variant of the device.
The OTP configuration cannot be read over I2C, so it is derived from
a compatible string instead.

Early revisions of the D0 order code require their OTP-enabled func-
tionality to be manually restored following a soft reset; this patch
accommodates this erratum as well.

Signed-off-by: default avatarJeff LaBundy <jeff@labundy.com>
Link: https://lore.kernel.org/r/ZZMaZbdk6iAKUjlm@nixie71


Signed-off-by: default avatarDmitry Torokhov <dmitry.torokhov@gmail.com>
parent 56c083e3
Loading
Loading
Loading
Loading
+89 −3
Original line number Diff line number Diff line
@@ -102,6 +102,11 @@
#define IQS269_MISC_B_TRACKING_UI_ENABLE	BIT(4)
#define IQS269_MISC_B_FILT_STR_SLIDER		GENMASK(1, 0)

#define IQS269_TOUCH_HOLD_SLIDER_SEL		0x89
#define IQS269_TOUCH_HOLD_DEFAULT		0x14
#define IQS269_TOUCH_HOLD_MS_MIN		256
#define IQS269_TOUCH_HOLD_MS_MAX		65280

#define IQS269_TIMEOUT_TAP_MS_MAX		4080
#define IQS269_TIMEOUT_SWIPE_MS_MAX		4080
#define IQS269_THRESH_SWIPE_MAX			255
@@ -151,6 +156,10 @@

#define IQS269_MAX_REG				0xFF

#define IQS269_OTP_OPTION_DEFAULT		0x00
#define IQS269_OTP_OPTION_TWS			0xD0
#define IQS269_OTP_OPTION_HOLD			BIT(7)

#define IQS269_NUM_CH				8
#define IQS269_NUM_SL				2

@@ -315,6 +324,7 @@ struct iqs269_private {
	struct input_dev *slider[IQS269_NUM_SL];
	unsigned int keycode[ARRAY_SIZE(iqs269_events) * IQS269_NUM_CH];
	unsigned int sl_code[IQS269_NUM_SL][IQS269_NUM_GESTURES];
	unsigned int otp_option;
	unsigned int ch_num;
	bool hall_enable;
	bool ati_current;
@@ -325,6 +335,14 @@ static enum iqs269_slider_id iqs269_slider_type(struct iqs269_private *iqs269,
{
	int i;

	/*
	 * Slider 1 is unavailable if the touch-and-hold option is enabled via
	 * OTP. In that case, the channel selection register is repurposed for
	 * the touch-and-hold timer ceiling.
	 */
	if (slider_num && (iqs269->otp_option & IQS269_OTP_OPTION_HOLD))
		return IQS269_SLIDER_NONE;

	if (!iqs269->sys_reg.slider_select[slider_num])
		return IQS269_SLIDER_NONE;

@@ -565,7 +583,8 @@ static int iqs269_parse_chan(struct iqs269_private *iqs269,
	if (fwnode_property_present(ch_node, "azoteq,slider0-select"))
		iqs269->sys_reg.slider_select[0] |= BIT(reg);

	if (fwnode_property_present(ch_node, "azoteq,slider1-select"))
	if (fwnode_property_present(ch_node, "azoteq,slider1-select") &&
	    !(iqs269->otp_option & IQS269_OTP_OPTION_HOLD))
		iqs269->sys_reg.slider_select[1] |= BIT(reg);

	ch_reg = &iqs269->sys_reg.ch_reg[reg];
@@ -990,7 +1009,43 @@ static int iqs269_parse_prop(struct iqs269_private *iqs269)
	sys_reg->blocking = 0;

	sys_reg->slider_select[0] = 0;

	/*
	 * If configured via OTP to do so, the device asserts a pulse on the
	 * GPIO4 pin for approximately 60 ms once a selected channel is held
	 * in a state of touch for a configurable length of time.
	 *
	 * In that case, the register used for slider 1 channel selection is
	 * repurposed for the touch-and-hold timer ceiling.
	 */
	if (iqs269->otp_option & IQS269_OTP_OPTION_HOLD) {
		if (!device_property_read_u32(&client->dev,
					      "azoteq,touch-hold-ms", &val)) {
			if (val < IQS269_TOUCH_HOLD_MS_MIN ||
			    val > IQS269_TOUCH_HOLD_MS_MAX) {
				dev_err(&client->dev,
					"Invalid touch-and-hold ceiling: %u\n",
					val);
				return -EINVAL;
			}

			sys_reg->slider_select[1] = val / 256;
		} else if (iqs269->ver_info.fw_num < IQS269_VER_INFO_FW_NUM_3) {
			/*
			 * The default touch-and-hold timer ceiling initially
			 * read from early revisions of silicon is invalid if
			 * the device experienced a soft reset between power-
			 * on and the read operation.
			 *
			 * To protect against this case, explicitly cache the
			 * default value so that it is restored each time the
			 * device is re-initialized.
			 */
			sys_reg->slider_select[1] = IQS269_TOUCH_HOLD_DEFAULT;
		}
	} else {
		sys_reg->slider_select[1] = 0;
	}

	sys_reg->event_mask = ~((u8)IQS269_EVENT_MASK_SYS);

@@ -1137,12 +1192,30 @@ static int iqs269_parse_prop(struct iqs269_private *iqs269)
	return 0;
}

static const struct reg_sequence iqs269_tws_init[] = {
	{ IQS269_TOUCH_HOLD_SLIDER_SEL, IQS269_TOUCH_HOLD_DEFAULT },
	{ 0xF0, 0x580F },
	{ 0xF0, 0x59EF },
};

static int iqs269_dev_init(struct iqs269_private *iqs269)
{
	int error;

	mutex_lock(&iqs269->lock);

	/*
	 * Early revisions of silicon require the following workaround in order
	 * to restore any OTP-enabled functionality after a soft reset.
	 */
	if (iqs269->otp_option == IQS269_OTP_OPTION_TWS &&
	    iqs269->ver_info.fw_num < IQS269_VER_INFO_FW_NUM_3) {
		error = regmap_multi_reg_write(iqs269->regmap, iqs269_tws_init,
					       ARRAY_SIZE(iqs269_tws_init));
		if (error)
			goto err_mutex;
	}

	error = regmap_update_bits(iqs269->regmap, IQS269_HALL_UI,
				   IQS269_HALL_UI_ENABLE,
				   iqs269->hall_enable ? ~0 : 0);
@@ -1779,6 +1852,8 @@ static int iqs269_probe(struct i2c_client *client)
	mutex_init(&iqs269->lock);
	init_completion(&iqs269->ati_done);

	iqs269->otp_option = (uintptr_t)device_get_match_data(&client->dev);

	error = regmap_raw_read(iqs269->regmap, IQS269_VER_INFO,
				&iqs269->ver_info, sizeof(iqs269->ver_info));
	if (error)
@@ -1889,7 +1964,18 @@ static int iqs269_resume(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(iqs269_pm, iqs269_suspend, iqs269_resume);

static const struct of_device_id iqs269_of_match[] = {
	{ .compatible = "azoteq,iqs269a" },
	{
		.compatible = "azoteq,iqs269a",
		.data = (void *)IQS269_OTP_OPTION_DEFAULT,
	},
	{
		.compatible = "azoteq,iqs269a-00",
		.data = (void *)IQS269_OTP_OPTION_DEFAULT,
	},
	{
		.compatible = "azoteq,iqs269a-d0",
		.data = (void *)IQS269_OTP_OPTION_TWS,
	},
	{ }
};
MODULE_DEVICE_TABLE(of, iqs269_of_match);