[PATCH v2 2/3] Input: aw86938 - add driver for Awinic AW86938

Griffin Kroah-Hartman posted 3 patches 1 week, 5 days ago
There is a newer version of this series
[PATCH v2 2/3] Input: aw86938 - add driver for Awinic AW86938
Posted by Griffin Kroah-Hartman 1 week, 5 days ago
Add support for the I2C-connected Awinic AW86938 LRA haptic driver.

The AW86938 has a similar but slightly different register layout. In
particular, the boost mode register values.
The AW86938 also has some extra features that aren't implemented
in this driver yet.

Signed-off-by: Griffin Kroah-Hartman <griffin.kroah@fairphone.com>
---
 drivers/input/misc/aw86927.c | 65 ++++++++++++++++++++++++++++++++++++--------
 1 file changed, 53 insertions(+), 12 deletions(-)

diff --git a/drivers/input/misc/aw86927.c b/drivers/input/misc/aw86927.c
index 8ad361239cfe3a888628b15e4dbdeed0c9ca3d1a..28ec6e42fd452a0edf1e1b9a9614e2723c6d9f93 100644
--- a/drivers/input/misc/aw86927.c
+++ b/drivers/input/misc/aw86927.c
@@ -43,6 +43,12 @@
 #define AW86927_PLAYCFG1_BST_VOUT_VREFSET_MASK	GENMASK(6, 0)
 #define AW86927_PLAYCFG1_BST_8500MV		0x50
 
+#define AW86938_PLAYCFG1_REG			0x06
+#define AW86938_PLAYCFG1_BST_MODE_MASK		GENMASK(5, 5)
+#define AW86938_PLAYCFG1_BST_MODE_BYPASS	0
+#define AW86938_PLAYCFG1_BST_VOUT_VREFSET_MASK	GENMASK(4, 0)
+#define AW86938_PLAYCFG1_BST_7000MV		0x11
+
 #define AW86927_PLAYCFG2_REG			0x07
 
 #define AW86927_PLAYCFG3_REG			0x08
@@ -140,6 +146,7 @@
 #define AW86927_CHIPIDH_REG			0x57
 #define AW86927_CHIPIDL_REG			0x58
 #define AW86927_CHIPID				0x9270
+#define AW86938_CHIPID				0x9380
 
 #define AW86927_TMCFG_REG			0x5b
 #define AW86927_TMCFG_UNLOCK			0x7d
@@ -173,7 +180,13 @@ enum aw86927_work_mode {
 	AW86927_RAM_MODE,
 };
 
+enum aw86927_model {
+	AW86927,
+	AW86938,
+};
+
 struct aw86927_data {
+	enum aw86927_model model;
 	struct work_struct play_work;
 	struct device *dev;
 	struct input_dev *input_dev;
@@ -377,7 +390,7 @@ static int aw86927_play_sine(struct aw86927_data *haptics)
 		return err;
 
 	/* set gain to value lower than 0x80 to avoid distorted playback */
-	err = regmap_write(haptics->regmap, AW86927_PLAYCFG2_REG, 0x7c);
+	err = regmap_write(haptics->regmap, AW86927_PLAYCFG2_REG, 0x45);
 	if (err)
 		return err;
 
@@ -565,13 +578,26 @@ static int aw86927_haptic_init(struct aw86927_data *haptics)
 	if (err)
 		return err;
 
-	err = regmap_update_bits(haptics->regmap,
-				 AW86927_PLAYCFG1_REG,
-				 AW86927_PLAYCFG1_BST_VOUT_VREFSET_MASK,
-				 FIELD_PREP(AW86927_PLAYCFG1_BST_VOUT_VREFSET_MASK,
-					    AW86927_PLAYCFG1_BST_8500MV));
-	if (err)
-		return err;
+	switch (haptics->model) {
+	case AW86927:
+		err = regmap_update_bits(haptics->regmap,
+				AW86927_PLAYCFG1_REG,
+				AW86927_PLAYCFG1_BST_VOUT_VREFSET_MASK,
+				FIELD_PREP(AW86927_PLAYCFG1_BST_VOUT_VREFSET_MASK,
+					AW86927_PLAYCFG1_BST_8500MV));
+		if (err)
+			return err;
+		break;
+	case AW86938:
+		err = regmap_update_bits(haptics->regmap,
+				AW86938_PLAYCFG1_REG,
+				AW86938_PLAYCFG1_BST_VOUT_VREFSET_MASK,
+				FIELD_PREP(AW86938_PLAYCFG1_BST_VOUT_VREFSET_MASK,
+					AW86938_PLAYCFG1_BST_7000MV));
+		if (err)
+			return err;
+		break;
+	}
 
 	err = regmap_update_bits(haptics->regmap,
 				 AW86927_PLAYCFG3_REG,
@@ -599,6 +625,9 @@ static int aw86927_ram_init(struct aw86927_data *haptics)
 				 FIELD_PREP(AW86927_SYSCTRL3_EN_RAMINIT_MASK,
 					    AW86927_SYSCTRL3_EN_RAMINIT_ON));
 
+	/* AW86938 wants a 1ms delay here */
+	usleep_range(1000, 1500);
+
 	/* Set base address for the start of the SRAM waveforms */
 	err = regmap_write(haptics->regmap,
 			   AW86927_BASEADDRH_REG, AW86927_BASEADDRH_VAL);
@@ -717,9 +746,19 @@ static int aw86927_detect(struct aw86927_data *haptics)
 
 	chip_id = be16_to_cpu(read_buf);
 
-	if (chip_id != AW86927_CHIPID) {
-		dev_err(haptics->dev, "Unexpected CHIPID value 0x%x\n", chip_id);
-		return -ENODEV;
+	switch (haptics->model) {
+	case AW86927:
+		if (chip_id != AW86927_CHIPID) {
+			dev_err(haptics->dev, "Unexpected CHIPID value 0x%x\n", chip_id);
+			return -ENODEV;
+		}
+		break;
+	case AW86938:
+		if (chip_id != AW86938_CHIPID) {
+			dev_err(haptics->dev, "Unexpected CHIPID value 0x%x\n", chip_id);
+			return -ENODEV;
+		}
+		break;
 	}
 
 	return 0;
@@ -736,6 +775,7 @@ static int aw86927_probe(struct i2c_client *client)
 
 	haptics->dev = &client->dev;
 	haptics->client = client;
+	haptics->model = (enum aw86927_model)device_get_match_data(&client->dev);
 
 	i2c_set_clientdata(client, haptics);
 
@@ -825,7 +865,8 @@ static int aw86927_probe(struct i2c_client *client)
 }
 
 static const struct of_device_id aw86927_of_id[] = {
-	{ .compatible = "awinic,aw86927" },
+	{ .compatible = "awinic,aw86927", .data = (void *)AW86927 },
+	{ .compatible = "awinic,aw86938", .data = (void *)AW86938 },
 	{ /* sentinel */ }
 };
 

-- 
2.43.0
Re: [PATCH v2 2/3] Input: aw86938 - add driver for Awinic AW86938
Posted by Dmitry Torokhov 1 week, 1 day ago
Hi Griffin,

On Wed, Jan 28, 2026 at 04:51:14PM +0100, Griffin Kroah-Hartman wrote:
> @@ -717,9 +746,19 @@ static int aw86927_detect(struct aw86927_data *haptics)
>  
>  	chip_id = be16_to_cpu(read_buf);
>  
> -	if (chip_id != AW86927_CHIPID) {
> -		dev_err(haptics->dev, "Unexpected CHIPID value 0x%x\n", chip_id);
> -		return -ENODEV;
> +	switch (haptics->model) {
> +	case AW86927:
> +		if (chip_id != AW86927_CHIPID) {
> +			dev_err(haptics->dev, "Unexpected CHIPID value 0x%x\n", chip_id);
> +			return -ENODEV;
> +		}

If we are able to query chip ID why do we need to have separate
compatibles? I would define chip data structure with differences between
variants and assign and use it instead of having separate compatible.

Thanks.

-- 
Dmitry
Re: [PATCH v2 2/3] Input: aw86938 - add driver for Awinic AW86938
Posted by Konrad Dybcio 1 week ago
On 2/1/26 2:49 AM, Dmitry Torokhov wrote:
> Hi Griffin,
> 
> On Wed, Jan 28, 2026 at 04:51:14PM +0100, Griffin Kroah-Hartman wrote:
>> @@ -717,9 +746,19 @@ static int aw86927_detect(struct aw86927_data *haptics)
>>  
>>  	chip_id = be16_to_cpu(read_buf);
>>  
>> -	if (chip_id != AW86927_CHIPID) {
>> -		dev_err(haptics->dev, "Unexpected CHIPID value 0x%x\n", chip_id);
>> -		return -ENODEV;
>> +	switch (haptics->model) {
>> +	case AW86927:
>> +		if (chip_id != AW86927_CHIPID) {
>> +			dev_err(haptics->dev, "Unexpected CHIPID value 0x%x\n", chip_id);
>> +			return -ENODEV;
>> +		}
> 
> If we are able to query chip ID why do we need to have separate
> compatibles? I would define chip data structure with differences between
> variants and assign and use it instead of having separate compatible.

dt-bindings guidelines explicitly call for this, a chipid comparison
then works as a safety net

Konrad
Re: [PATCH v2 2/3] Input: aw86938 - add driver for Awinic AW86938
Posted by Krzysztof Kozlowski 4 days, 9 hours ago
On Mon, Feb 02, 2026 at 11:12:26AM +0100, Konrad Dybcio wrote:
> On 2/1/26 2:49 AM, Dmitry Torokhov wrote:
> > Hi Griffin,
> > 
> > On Wed, Jan 28, 2026 at 04:51:14PM +0100, Griffin Kroah-Hartman wrote:
> >> @@ -717,9 +746,19 @@ static int aw86927_detect(struct aw86927_data *haptics)
> >>  
> >>  	chip_id = be16_to_cpu(read_buf);
> >>  
> >> -	if (chip_id != AW86927_CHIPID) {
> >> -		dev_err(haptics->dev, "Unexpected CHIPID value 0x%x\n", chip_id);
> >> -		return -ENODEV;
> >> +	switch (haptics->model) {
> >> +	case AW86927:
> >> +		if (chip_id != AW86927_CHIPID) {
> >> +			dev_err(haptics->dev, "Unexpected CHIPID value 0x%x\n", chip_id);
> >> +			return -ENODEV;
> >> +		}
> > 
> > If we are able to query chip ID why do we need to have separate
> > compatibles? I would define chip data structure with differences between
> > variants and assign and use it instead of having separate compatible.
> 
> dt-bindings guidelines explicitly call for this, a chipid comparison

No, they don't. If devices offer autodetection, then they are in fact
fully compatible for the SW.

Best regards,
Krzysztof
Re: [PATCH v2 2/3] Input: aw86938 - add driver for Awinic AW86938
Posted by Luca Weiss 1 week ago
Hi Konrad,

On Mon Feb 2, 2026 at 11:12 AM CET, Konrad Dybcio wrote:
> On 2/1/26 2:49 AM, Dmitry Torokhov wrote:
>> Hi Griffin,
>> 
>> On Wed, Jan 28, 2026 at 04:51:14PM +0100, Griffin Kroah-Hartman wrote:
>>> @@ -717,9 +746,19 @@ static int aw86927_detect(struct aw86927_data *haptics)
>>>  
>>>  	chip_id = be16_to_cpu(read_buf);
>>>  
>>> -	if (chip_id != AW86927_CHIPID) {
>>> -		dev_err(haptics->dev, "Unexpected CHIPID value 0x%x\n", chip_id);
>>> -		return -ENODEV;
>>> +	switch (haptics->model) {
>>> +	case AW86927:
>>> +		if (chip_id != AW86927_CHIPID) {
>>> +			dev_err(haptics->dev, "Unexpected CHIPID value 0x%x\n", chip_id);
>>> +			return -ENODEV;
>>> +		}
>> 
>> If we are able to query chip ID why do we need to have separate
>> compatibles? I would define chip data structure with differences between
>> variants and assign and use it instead of having separate compatible.
>
> dt-bindings guidelines explicitly call for this, a chipid comparison
> then works as a safety net

Are you saying, that

1. we should enforce dt-bindings == CHIP_ID (what's currently done)

or

2. we should have both compatibles with no handling based on compatible,
   but only use CHIP_ID at runtime to change behavior

Regards
Luca
Re: [PATCH v2 2/3] Input: aw86938 - add driver for Awinic AW86938
Posted by Konrad Dybcio 1 week ago
On 2/2/26 11:14 AM, Luca Weiss wrote:
> Hi Konrad,
> 
> On Mon Feb 2, 2026 at 11:12 AM CET, Konrad Dybcio wrote:
>> On 2/1/26 2:49 AM, Dmitry Torokhov wrote:
>>> Hi Griffin,
>>>
>>> On Wed, Jan 28, 2026 at 04:51:14PM +0100, Griffin Kroah-Hartman wrote:
>>>> @@ -717,9 +746,19 @@ static int aw86927_detect(struct aw86927_data *haptics)
>>>>  
>>>>  	chip_id = be16_to_cpu(read_buf);
>>>>  
>>>> -	if (chip_id != AW86927_CHIPID) {
>>>> -		dev_err(haptics->dev, "Unexpected CHIPID value 0x%x\n", chip_id);
>>>> -		return -ENODEV;
>>>> +	switch (haptics->model) {
>>>> +	case AW86927:
>>>> +		if (chip_id != AW86927_CHIPID) {
>>>> +			dev_err(haptics->dev, "Unexpected CHIPID value 0x%x\n", chip_id);
>>>> +			return -ENODEV;
>>>> +		}
>>>
>>> If we are able to query chip ID why do we need to have separate
>>> compatibles? I would define chip data structure with differences between
>>> variants and assign and use it instead of having separate compatible.
>>
>> dt-bindings guidelines explicitly call for this, a chipid comparison
>> then works as a safety net
> 
> Are you saying, that
> 
> 1. we should enforce dt-bindings == CHIP_ID (what's currently done)

This

> 
> or
> 
> 2. we should have both compatibles with no handling based on compatible,
>    but only use CHIP_ID at runtime to change behavior

This is spaghetti

Konrad
Re: [PATCH v2 2/3] Input: aw86938 - add driver for Awinic AW86938
Posted by Dmitry Torokhov 1 week ago
On Mon, Feb 02, 2026 at 11:19:36AM +0100, Konrad Dybcio wrote:
> On 2/2/26 11:14 AM, Luca Weiss wrote:
> > Hi Konrad,
> > 
> > On Mon Feb 2, 2026 at 11:12 AM CET, Konrad Dybcio wrote:
> >> On 2/1/26 2:49 AM, Dmitry Torokhov wrote:
> >>> Hi Griffin,
> >>>
> >>> On Wed, Jan 28, 2026 at 04:51:14PM +0100, Griffin Kroah-Hartman wrote:
> >>>> @@ -717,9 +746,19 @@ static int aw86927_detect(struct aw86927_data *haptics)
> >>>>  
> >>>>  	chip_id = be16_to_cpu(read_buf);
> >>>>  
> >>>> -	if (chip_id != AW86927_CHIPID) {
> >>>> -		dev_err(haptics->dev, "Unexpected CHIPID value 0x%x\n", chip_id);
> >>>> -		return -ENODEV;
> >>>> +	switch (haptics->model) {
> >>>> +	case AW86927:
> >>>> +		if (chip_id != AW86927_CHIPID) {
> >>>> +			dev_err(haptics->dev, "Unexpected CHIPID value 0x%x\n", chip_id);
> >>>> +			return -ENODEV;
> >>>> +		}
> >>>
> >>> If we are able to query chip ID why do we need to have separate
> >>> compatibles? I would define chip data structure with differences between
> >>> variants and assign and use it instead of having separate compatible.
> >>
> >> dt-bindings guidelines explicitly call for this, a chipid comparison
> >> then works as a safety net
> > 
> > Are you saying, that
> > 
> > 1. we should enforce dt-bindings == CHIP_ID (what's currently done)
> 
> This

No. If there is a compatible chip with different ID (for whatever reason
- maybe there is additional functionality that either board does not
need or the driver does not implement) we absolutely should not refuse
to bind the driver.

Hint: this thing is called _compatible_ for a reason.

> 
> > 
> > or
> > 
> > 2. we should have both compatibles with no handling based on compatible,
> >    but only use CHIP_ID at runtime to change behavior
> 
> This is spaghetti

I really do not understand the aversion of DT maintainers to generic
compatibles. We see this in I2C HID where we keep adding compatibles
for what could be described via device properties.

Thanks.

-- 
Dmitry
Re: [PATCH v2 2/3] Input: aw86938 - add driver for Awinic AW86938
Posted by Konrad Dybcio 1 week ago
On 2/2/26 12:04 PM, Dmitry Torokhov wrote:
> On Mon, Feb 02, 2026 at 11:19:36AM +0100, Konrad Dybcio wrote:
>> On 2/2/26 11:14 AM, Luca Weiss wrote:
>>> Hi Konrad,
>>>
>>> On Mon Feb 2, 2026 at 11:12 AM CET, Konrad Dybcio wrote:
>>>> On 2/1/26 2:49 AM, Dmitry Torokhov wrote:
>>>>> Hi Griffin,
>>>>>
>>>>> On Wed, Jan 28, 2026 at 04:51:14PM +0100, Griffin Kroah-Hartman wrote:
>>>>>> @@ -717,9 +746,19 @@ static int aw86927_detect(struct aw86927_data *haptics)
>>>>>>  
>>>>>>  	chip_id = be16_to_cpu(read_buf);
>>>>>>  
>>>>>> -	if (chip_id != AW86927_CHIPID) {
>>>>>> -		dev_err(haptics->dev, "Unexpected CHIPID value 0x%x\n", chip_id);
>>>>>> -		return -ENODEV;
>>>>>> +	switch (haptics->model) {
>>>>>> +	case AW86927:
>>>>>> +		if (chip_id != AW86927_CHIPID) {
>>>>>> +			dev_err(haptics->dev, "Unexpected CHIPID value 0x%x\n", chip_id);
>>>>>> +			return -ENODEV;
>>>>>> +		}
>>>>>
>>>>> If we are able to query chip ID why do we need to have separate
>>>>> compatibles? I would define chip data structure with differences between
>>>>> variants and assign and use it instead of having separate compatible.
>>>>
>>>> dt-bindings guidelines explicitly call for this, a chipid comparison
>>>> then works as a safety net
>>>
>>> Are you saying, that
>>>
>>> 1. we should enforce dt-bindings == CHIP_ID (what's currently done)
>>
>> This
> 
> No. If there is a compatible chip with different ID (for whatever reason
> - maybe there is additional functionality that either board does not
> need or the driver does not implement) we absolutely should not refuse
> to bind the driver.
> 
> Hint: this thing is called _compatible_ for a reason.

Right, the reason you have in mind is fulfilled by fallback compatibles

(i.e. "vendor,actualchipname", "vendor,similarchipname" where the driver
only considers the latter becuase the software interface hasn't changed)

> 
>>
>>>
>>> or
>>>
>>> 2. we should have both compatibles with no handling based on compatible,
>>>    but only use CHIP_ID at runtime to change behavior
>>
>> This is spaghetti
> 
> I really do not understand the aversion of DT maintainers to generic
> compatibles. We see this in I2C HID where we keep adding compatibles
> for what could be described via device properties.

This is because it's the only way to allow for retroactive changes that
do not require changing firmware. That's why ACPI carries new identifiers
for even very slightly different devices too. Once the firmware containing
(ACPI tables / DTB) is put on a production device, it is generally not
going to ever change.

CHIP_ID registers are a good tool to validate that the author of the
firmware table is doing the right thing, but solely relying on them
encourages creating a "vendor,haptic" compatible, which I'm sure you'll
agree is totally meaningless.

That's especially if the naming scheme makes no sense and you can't
even factor out a common wildcard-name (which also happens to be the case
quite often)

Plus a compatible is used to restrict/modify the set of allowed/required
properties, so having an "actual" compatible is required for schema
validation to work

Konrad
Re: [PATCH v2 2/3] Input: aw86938 - add driver for Awinic AW86938
Posted by Dmitry Torokhov 6 days, 12 hours ago
On Mon, Feb 02, 2026 at 04:11:51PM +0100, Konrad Dybcio wrote:
> On 2/2/26 12:04 PM, Dmitry Torokhov wrote:
> > On Mon, Feb 02, 2026 at 11:19:36AM +0100, Konrad Dybcio wrote:
> >> On 2/2/26 11:14 AM, Luca Weiss wrote:
> >>> Hi Konrad,
> >>>
> >>> On Mon Feb 2, 2026 at 11:12 AM CET, Konrad Dybcio wrote:
> >>>> On 2/1/26 2:49 AM, Dmitry Torokhov wrote:
> >>>>> Hi Griffin,
> >>>>>
> >>>>> On Wed, Jan 28, 2026 at 04:51:14PM +0100, Griffin Kroah-Hartman wrote:
> >>>>>> @@ -717,9 +746,19 @@ static int aw86927_detect(struct aw86927_data *haptics)
> >>>>>>  
> >>>>>>  	chip_id = be16_to_cpu(read_buf);
> >>>>>>  
> >>>>>> -	if (chip_id != AW86927_CHIPID) {
> >>>>>> -		dev_err(haptics->dev, "Unexpected CHIPID value 0x%x\n", chip_id);
> >>>>>> -		return -ENODEV;
> >>>>>> +	switch (haptics->model) {
> >>>>>> +	case AW86927:
> >>>>>> +		if (chip_id != AW86927_CHIPID) {
> >>>>>> +			dev_err(haptics->dev, "Unexpected CHIPID value 0x%x\n", chip_id);
> >>>>>> +			return -ENODEV;
> >>>>>> +		}
> >>>>>
> >>>>> If we are able to query chip ID why do we need to have separate
> >>>>> compatibles? I would define chip data structure with differences between
> >>>>> variants and assign and use it instead of having separate compatible.
> >>>>
> >>>> dt-bindings guidelines explicitly call for this, a chipid comparison
> >>>> then works as a safety net
> >>>
> >>> Are you saying, that
> >>>
> >>> 1. we should enforce dt-bindings == CHIP_ID (what's currently done)
> >>
> >> This
> > 
> > No. If there is a compatible chip with different ID (for whatever reason
> > - maybe there is additional functionality that either board does not
> > need or the driver does not implement) we absolutely should not refuse
> > to bind the driver.
> > 
> > Hint: this thing is called _compatible_ for a reason.
> 
> Right, the reason you have in mind is fulfilled by fallback compatibles
> 
> (i.e. "vendor,actualchipname", "vendor,similarchipname" where the driver
> only considers the latter becuase the software interface hasn't changed)

And having chip_id checks will break this...

> 
> > 
> >>
> >>>
> >>> or
> >>>
> >>> 2. we should have both compatibles with no handling based on compatible,
> >>>    but only use CHIP_ID at runtime to change behavior
> >>
> >> This is spaghetti
> > 
> > I really do not understand the aversion of DT maintainers to generic
> > compatibles. We see this in I2C HID where we keep adding compatibles
> > for what could be described via device properties.
> 
> This is because it's the only way to allow for retroactive changes that
> do not require changing firmware. That's why ACPI carries new identifiers
> for even very slightly different devices too. Once the firmware containing
> (ACPI tables / DTB) is put on a production device, it is generally not
> going to ever change.

They are actually solving slightly different problem. In ACPI world they
allocate a new ID to represent a peripheral in a given design, down to
it's firmware behavior. It encodes much more than chip ID that DT
maintainers want to key off of.

> 
> CHIP_ID registers are a good tool to validate that the author of the
> firmware table is doing the right thing, but solely relying on them
> encourages creating a "vendor,haptic" compatible, which I'm sure you'll
> agree is totally meaningless.

Is it? If a piece of hardware speaks i2c-hid protocol why do I need to
know the exact chip that is being used? Depending on the chassis and the
size of the sensing element and the version of the firmware that is
loaded into it the behavior and timings of the same chip may be very
different.

> 
> That's especially if the naming scheme makes no sense and you can't
> even factor out a common wildcard-name (which also happens to be the case
> quite often)
> 
> Plus a compatible is used to restrict/modify the set of allowed/required
> properties, so having an "actual" compatible is required for schema
> validation to work

Yes, in cases where there is not a common set of properties having
different compatibles makes sense. But in cases when the device is
supposed to have vendor-agnostic behavior insisting on myriad
compatibles makes little sense.

Thanks.

-- 
Dmitry
Re: [PATCH v2 2/3] Input: aw86938 - add driver for Awinic AW86938
Posted by Konrad Dybcio 6 days, 11 hours ago
On 2/3/26 10:49 AM, Dmitry Torokhov wrote:
> On Mon, Feb 02, 2026 at 04:11:51PM +0100, Konrad Dybcio wrote:
>> On 2/2/26 12:04 PM, Dmitry Torokhov wrote:
>>> On Mon, Feb 02, 2026 at 11:19:36AM +0100, Konrad Dybcio wrote:
>>>> On 2/2/26 11:14 AM, Luca Weiss wrote:
>>>>> Hi Konrad,
>>>>>
>>>>> On Mon Feb 2, 2026 at 11:12 AM CET, Konrad Dybcio wrote:
>>>>>> On 2/1/26 2:49 AM, Dmitry Torokhov wrote:
>>>>>>> Hi Griffin,
>>>>>>>
>>>>>>> On Wed, Jan 28, 2026 at 04:51:14PM +0100, Griffin Kroah-Hartman wrote:
>>>>>>>> @@ -717,9 +746,19 @@ static int aw86927_detect(struct aw86927_data *haptics)
>>>>>>>>  
>>>>>>>>  	chip_id = be16_to_cpu(read_buf);
>>>>>>>>  
>>>>>>>> -	if (chip_id != AW86927_CHIPID) {
>>>>>>>> -		dev_err(haptics->dev, "Unexpected CHIPID value 0x%x\n", chip_id);
>>>>>>>> -		return -ENODEV;
>>>>>>>> +	switch (haptics->model) {
>>>>>>>> +	case AW86927:
>>>>>>>> +		if (chip_id != AW86927_CHIPID) {
>>>>>>>> +			dev_err(haptics->dev, "Unexpected CHIPID value 0x%x\n", chip_id);
>>>>>>>> +			return -ENODEV;
>>>>>>>> +		}
>>>>>>>
>>>>>>> If we are able to query chip ID why do we need to have separate
>>>>>>> compatibles? I would define chip data structure with differences between
>>>>>>> variants and assign and use it instead of having separate compatible.
>>>>>>
>>>>>> dt-bindings guidelines explicitly call for this, a chipid comparison
>>>>>> then works as a safety net
>>>>>
>>>>> Are you saying, that
>>>>>
>>>>> 1. we should enforce dt-bindings == CHIP_ID (what's currently done)
>>>>
>>>> This
>>>
>>> No. If there is a compatible chip with different ID (for whatever reason
>>> - maybe there is additional functionality that either board does not
>>> need or the driver does not implement) we absolutely should not refuse
>>> to bind the driver.
>>>
>>> Hint: this thing is called _compatible_ for a reason.
>>
>> Right, the reason you have in mind is fulfilled by fallback compatibles
>>
>> (i.e. "vendor,actualchipname", "vendor,similarchipname" where the driver
>> only considers the latter becuase the software interface hasn't changed)
> 
> And having chip_id checks will break this...

Depends on how they're implemented and how different the chips are.

If the software interface is exactly 1:1, with the only difference in the
ID register, something like

if (chipid == SIMILARCHIPNAME_ID || chipid == ACTUALCHIPNAME_ID)
	...

would be fitting.

However, more often than not, like in this case, there's actual differences
that need to be taken into account, meaning we already need to act upon
the "actual" compatible

> 
>>
>>>
>>>>
>>>>>
>>>>> or
>>>>>
>>>>> 2. we should have both compatibles with no handling based on compatible,
>>>>>    but only use CHIP_ID at runtime to change behavior
>>>>
>>>> This is spaghetti
>>>
>>> I really do not understand the aversion of DT maintainers to generic
>>> compatibles. We see this in I2C HID where we keep adding compatibles
>>> for what could be described via device properties.
>>
>> This is because it's the only way to allow for retroactive changes that
>> do not require changing firmware. That's why ACPI carries new identifiers
>> for even very slightly different devices too. Once the firmware containing
>> (ACPI tables / DTB) is put on a production device, it is generally not
>> going to ever change.
> 
> They are actually solving slightly different problem. In ACPI world they
> allocate a new ID to represent a peripheral in a given design, down to
> it's firmware behavior. It encodes much more than chip ID that DT
> maintainers want to key off of.

DT sort of does this to. In the Qualcomm world, how you get to interact
with the platform changes dramatically depending on the firmware flavor
it's flashed with (which I'd hope to see go away one day..) - if you have
a Chrome firmware, you're basically free/required to configure everything
from Linux. With Android firmware, much of that heavy lifting must be done
by the hypervisor or the secure world. With Windows firmware, you get the
Android experience + UEFI services. And at the tail end of the scale,
there's the automotive firmware where you don't even get to toggle clocks,
but instead all peripherals' power and performance states are exposed
through dozens of SCMI servers..

Somehow we can try and be smart, deducing the behavior based on the
properties present in DT, but often times, a separate compatible for
"this SoC except with this firmware" needs to exist, as the OS-accessible
software interface is simply different, as if this wasn't the same SoC
anymore.

> 
>>
>> CHIP_ID registers are a good tool to validate that the author of the
>> firmware table is doing the right thing, but solely relying on them
>> encourages creating a "vendor,haptic" compatible, which I'm sure you'll
>> agree is totally meaningless.
> 
> Is it? If a piece of hardware speaks i2c-hid protocol why do I need to
> know the exact chip that is being used? Depending on the chassis and the
> size of the sensing element and the version of the firmware that is
> loaded into it the behavior and timings of the same chip may be very
> different.

I agree this argument gets overused at times

>>
>> That's especially if the naming scheme makes no sense and you can't
>> even factor out a common wildcard-name (which also happens to be the case
>> quite often)
>>
>> Plus a compatible is used to restrict/modify the set of allowed/required
>> properties, so having an "actual" compatible is required for schema
>> validation to work
> 
> Yes, in cases where there is not a common set of properties having
> different compatibles makes sense. But in cases when the device is
> supposed to have vendor-agnostic behavior insisting on myriad
> compatibles makes little sense.

Some people may be thrown off by the golden rule of implementing standards,
which is to break or bend them immediately, claiming full compatibility.

But for cases like hid-over-i2c, I symphatize with the "no one needs
to know if it's a synaptics a00001 or a synaptics a00002" sentiment

Konrad
Re: [PATCH v2 2/3] Input: aw86938 - add driver for Awinic AW86938
Posted by kernel test robot 1 week, 2 days ago
Hi Griffin,

kernel test robot noticed the following build warnings:

[auto build test WARNING on 0364de6be161e2360cbb1f26d5aff5b343ef7bb0]

url:    https://github.com/intel-lab-lkp/linux/commits/Griffin-Kroah-Hartman/dt-bindings-input-awinic-aw86927-Add-Awinic-AW86938/20260129-000753
base:   0364de6be161e2360cbb1f26d5aff5b343ef7bb0
patch link:    https://lore.kernel.org/r/20260128-aw86938-driver-v2-2-b51ee086aaf5%40fairphone.com
patch subject: [PATCH v2 2/3] Input: aw86938 - add driver for Awinic AW86938
config: sparc64-allmodconfig (https://download.01.org/0day-ci/archive/20260131/202601311117.t00gEixW-lkp@intel.com/config)
compiler: clang version 22.0.0git (https://github.com/llvm/llvm-project 9b8addffa70cee5b2acc5454712d9cf78ce45710)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260131/202601311117.t00gEixW-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202601311117.t00gEixW-lkp@intel.com/

All warnings (new ones prefixed by >>):

>> drivers/input/misc/aw86927.c:778:19: warning: cast to smaller integer type 'enum aw86927_model' from 'const void *' [-Wvoid-pointer-to-enum-cast]
     778 |         haptics->model = (enum aw86927_model)device_get_match_data(&client->dev);
         |                          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   1 warning generated.


vim +778 drivers/input/misc/aw86927.c

   766	
   767	static int aw86927_probe(struct i2c_client *client)
   768	{
   769		struct aw86927_data *haptics;
   770		int err;
   771	
   772		haptics = devm_kzalloc(&client->dev, sizeof(struct aw86927_data), GFP_KERNEL);
   773		if (!haptics)
   774			return -ENOMEM;
   775	
   776		haptics->dev = &client->dev;
   777		haptics->client = client;
 > 778		haptics->model = (enum aw86927_model)device_get_match_data(&client->dev);
   779	
   780		i2c_set_clientdata(client, haptics);
   781	
   782		haptics->regmap = devm_regmap_init_i2c(client, &aw86927_regmap_config);
   783		if (IS_ERR(haptics->regmap))
   784			return dev_err_probe(haptics->dev, PTR_ERR(haptics->regmap),
   785						"Failed to allocate register map\n");
   786	
   787		haptics->input_dev = devm_input_allocate_device(haptics->dev);
   788		if (!haptics->input_dev)
   789			return -ENOMEM;
   790	
   791		haptics->reset_gpio = devm_gpiod_get(haptics->dev, "reset", GPIOD_OUT_HIGH);
   792		if (IS_ERR(haptics->reset_gpio))
   793			return dev_err_probe(haptics->dev, PTR_ERR(haptics->reset_gpio),
   794					     "Failed to get reset gpio\n");
   795	
   796		/* Hardware reset */
   797		aw86927_hw_reset(haptics);
   798	
   799		/* Software reset */
   800		err = regmap_write(haptics->regmap, AW86927_RSTCFG_REG, AW86927_RSTCFG_SOFTRST);
   801		if (err)
   802			return dev_err_probe(haptics->dev, err,	"Failed Software reset\n");
   803	
   804		/* Wait ~3ms until I2C is accessible */
   805		usleep_range(3000, 3500);
   806	
   807		err = aw86927_detect(haptics);
   808		if (err)
   809			return dev_err_probe(haptics->dev, err, "Failed to find chip\n");
   810	
   811		/* IRQ config */
   812		err = regmap_write(haptics->regmap, AW86927_SYSCTRL4_REG,
   813				   FIELD_PREP(AW86927_SYSCTRL4_INT_MODE_MASK,
   814					      AW86927_SYSCTRL4_INT_MODE_EDGE) |
   815					FIELD_PREP(AW86927_SYSCTRL4_INT_EDGE_MODE_MASK,
   816						   AW86927_SYSCTRL4_INT_EDGE_MODE_POS));
   817		if (err)
   818			return dev_err_probe(haptics->dev, err, "Failed to configure interrupt modes\n");
   819	
   820		err = regmap_write(haptics->regmap, AW86927_SYSINTM_REG,
   821				   AW86927_SYSINTM_BST_OVPM |
   822					AW86927_SYSINTM_FF_AEM |
   823					AW86927_SYSINTM_FF_AFM |
   824					AW86927_SYSINTM_DONEM);
   825		if (err)
   826			return dev_err_probe(haptics->dev, err, "Failed to configure interrupt masks\n");
   827	
   828		err = devm_request_threaded_irq(haptics->dev, client->irq, NULL,
   829						aw86927_irq, IRQF_ONESHOT, NULL, haptics);
   830		if (err)
   831			return dev_err_probe(haptics->dev, err, "Failed to request threaded irq\n");
   832	
   833		INIT_WORK(&haptics->play_work, aw86927_haptics_play_work);
   834	
   835		haptics->input_dev->name = "aw86927-haptics";
   836		haptics->input_dev->close = aw86927_close;
   837	
   838		input_set_drvdata(haptics->input_dev, haptics);
   839		input_set_capability(haptics->input_dev, EV_FF, FF_RUMBLE);
   840	
   841		err = input_ff_create_memless(haptics->input_dev, NULL, aw86927_haptics_play);
   842		if (err)
   843			return dev_err_probe(haptics->dev, err, "Failed to create FF dev\n");
   844	
   845		/* Set up registers */
   846		err = aw86927_play_mode(haptics, AW86927_STANDBY_MODE);
   847		if (err)
   848			return dev_err_probe(haptics->dev, err,
   849					     "Failed to enter standby for Haptic init\n");
   850	
   851		err = aw86927_haptic_init(haptics);
   852		if (err)
   853			return dev_err_probe(haptics->dev, err, "Haptic init failed\n");
   854	
   855		/* RAM init, upload the waveform for playback */
   856		err = aw86927_ram_init(haptics);
   857		if (err)
   858			return dev_err_probe(haptics->dev, err, "Failed to init aw86927 sram\n");
   859	
   860		err = input_register_device(haptics->input_dev);
   861		if (err)
   862			return dev_err_probe(haptics->dev, err, "Failed to register input device\n");
   863	
   864		return 0;
   865	}
   866	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki