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: Jeff LaBundy <jeff@labundy.com> Link: https://lore.kernel.org/r/ZZMaZbdk6iAKUjlm@nixie71 Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
This commit is contained in:
parent
56c083e3f5
commit
992bbc9e9a
@ -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;
|
||||
sys_reg->slider_select[1] = 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);
|
||||
|
Loading…
Reference in New Issue
Block a user