diff mbox series

[v2,2/4] Input: mt-matrix-keypad: Add Bosch mt matrix keypad driver

Message ID 20220506072737.1590-2-Gireesh.Hiremath@in.bosch.com
State Superseded
Headers show
Series [v2,1/4] ARM: dts: am335x: Guardian: switch to AM33XX_PADCONF pinmux macro | expand

Commit Message

Gireesh.Hiremath@in.bosch.com May 6, 2022, 7:27 a.m. UTC
From: Gireesh Hiremath <Gireesh.Hiremath@in.bosch.com>

add support for keypad driver running on Bosch Guardian
Dtect board using TI-am335x cpu. Driver implementation
is based on matrix_keypad.c

Signed-off-by: Gireesh Hiremath <Gireesh.Hiremath@in.bosch.com>
---
Hi Marco,

Changes since v1: resolved compilation warnings

>On 22-05-04, Gireesh.Hiremath@in.bosch.com wrote:
>> From: Gireesh Hiremath <Gireesh.Hiremath@in.bosch.com>
>>
>> The existing matric_keypad.c use different gpio line for row and colunm,
>> where in mt_matrix_kepad.c use same gpio line for row as well as column.
>> a key can be placed at each intersection of a unique row number
>> not equal to a unique column and they are diagonally symmetric.
>> Advantage of this is with existed gpio line we can get more keys
>>
>> example: in matrix_keypad.c for 5 gpio line possible matrix is 2X3 or 3X2
>> and maximum possible keys are 6 but
>> in mt_matrix_kepad.c for same 5 gpio line possible matrix is 5X5 and maximum
>> possible buttons are 10, below table will discribe that
>
>Nobody should stop you to increase the amount of max. possible keys, so
>this isn't a real block.
>> 	------------------------------------------------------
>> 	|Row\Col |GPIO 0 | GPIO 1 | GPIO 2 | GPIO 3 | GPIO 4 |
>> 	------------------------------------------------------
>> 	| GPIO 0 |  X    | KEY_9  | KEY_2  | KEY_3  | KEY_1  |
>> 	------------------------------------------------------
>> 	| GPIO 1 | KEY_9 |  X     | KEY_6  | KEY_5  |  KEY_0 |
>> 	------------------------------------------------------
>> 	| GPIO 2 | KEY_2 | KEY_6  |  X     | KEY_4  | KEY_7  |
>> 	------------------------------------------------------
>> 	| GPIO 3 | KEY_3 | KEY_5  | KEY_4  |  X     | KEY_8  |
>> 	------------------------------------------------------
>> 	| GPIO 4 | KEY_1 |  KEY_0 | KEY_7  | KEY_8  |  X     |
>> 	------------------------------------------------------
>> 	X - invalid key
>> 	KEY_x - preferred key code
>
>That should be pointed somewhere very clearly, thanks for the
>description. Also what is than the benefit of the original matrix_keypad
>driver?

we have special keypad for Bosch measuring tools, which is not completely
matric keypad so we have derived from matrix_kepad.c to make our keypad
to work.

In this keypad there may or may not have keymap for all gpio line
as below

	------------------------------------------------------
	|Row\Col |GPIO 0 | GPIO 1 | GPIO 2 | GPIO 3 | GPIO 4 |
	------------------------------------------------------
	| GPIO 0 |  X    | KEY_9  | KEY_2  |  X     | KEY_1  |
	------------------------------------------------------
	| GPIO 1 | KEY_9 |  X     | KEY_6  |  X     |   X    |
	------------------------------------------------------
	| GPIO 2 | KEY_2 | KEY_6  |  X     | KEY_4  | KEY_7  |
	------------------------------------------------------
	| GPIO 3 |  X    |  X     | KEY_4  |  X     | KEY_8  |
	------------------------------------------------------
	| GPIO 4 | KEY_1 |  X     | KEY_7  | KEY_8  |  X     |
	------------------------------------------------------
   X - invalid key

example DTS

    line-gpios = <
             &gpio1 24 1     /*gpio_56*/
             &gpio1 23 1     /*gpio_55*/
             &gpio1 22 1     /*gpio_54*/
             &gpio1 20 1     /*gpio_52*/
             &gpio1 16 1     /*gpio_48*/
     >;
     linux,keymap = <
             0x00000000 /* row 0, col 0, KEY_RESERVED */
             0x0001000a /* row 0, col 1, KEY_9 */
             0x00020003 /* row 0, col 2, KEY_2 */
             0x00030000 /* row 0, col 3, KEY_RESERVED */
             0x00040002 /* row 0, col 4, KEY_1 */
             0x0100000a /* row 1, col 0, KEY_9 */
             0x01010000 /* row 1, col 1, KEY_RESERVED */
             0x01020007 /* row 1, col 2, KEY_6 */
             0x01030000 /* row 1, col 3, KEY_RESERVED */
             0x01040000 /* row 1, col 4, KEY_RESERVED */
             0x02000003 /* row 2, col 0, KEY_2 */
             0x02010007 /* row 2, col 1, KEY_6 */
             0x02020000 /* row 2, col 2, KEY_RESERVED */
             0x02030005 /* row 2, col 3, KEY_4 */
             0x02040008 /* row 2, col 4, KEY_7 */
             0x03000000 /* row 3, col 0, KEY_RESERVED */
             0x03010000 /* row 3, col 1, KEY_RESERVED */
             0x03020005 /* row 3, col 2, KEY_4 */
             0x03030000 /* row 3, col 3, KEY_RESERVED */
             0x03040009 /* row 3, col 4, KEY_8 */
             0x04000002 /* row 4, col 0, KEY_1 */
             0x04010000 /* row 4, col 1, KEY_RESERVED */
             0x04020008 /* row 4, col 2, KEY_7 */
             0x04030009 /* row 4, col 3, KEY_8 */
             0x04040000 /* row 4, col 4, KEY_RESERVED */
     >;

>
>> both matric_keypad.c and mt_matrix_kepad.c logically operate differently,
>> my openion is not to merge both.
>
>IMHO from the user/system-integrator pov it is looking the same and so
>one driver should be fine. To distinguish between both modes we could
>add dt-property or add a new dt-compatible like "gpio-matrix-keypad-v2".
>

as mentioned above our keypad is not complete matrix keypad  and it will
not be compatible with matrix_keypad diver. that is the reason we derived
mt matrix keypad driver.

to avoid confusion, we will rename the driver as bosch_mt_keypad.c
if you suggest.

>Regards,
>  Marco

Regards
Gireesh Hiremath

 drivers/input/keyboard/Kconfig            |  10 +
 drivers/input/keyboard/Makefile           |   1 +
 drivers/input/keyboard/mt_matrix_keypad.c | 741 ++++++++++++++++++++++
 include/linux/input/mt_matrix_keypad.h    |  85 +++
 4 files changed, 837 insertions(+)
 create mode 100644 drivers/input/keyboard/mt_matrix_keypad.c
 create mode 100644 include/linux/input/mt_matrix_keypad.h

Comments

Krzysztof Kozlowski May 7, 2022, 3:46 p.m. UTC | #1
On 06/05/2022 09:27, Gireesh.Hiremath@in.bosch.com wrote:
>>
>>> both matric_keypad.c and mt_matrix_kepad.c logically operate differently,
>>> my openion is not to merge both.
>>
>> IMHO from the user/system-integrator pov it is looking the same and so
>> one driver should be fine. To distinguish between both modes we could
>> add dt-property or add a new dt-compatible like "gpio-matrix-keypad-v2".
>>
> 
> as mentioned above our keypad is not complete matrix keypad  and it will
> not be compatible with matrix_keypad diver. that is the reason we derived
> mt matrix keypad driver.
> 
> to avoid confusion, we will rename the driver as bosch_mt_keypad.c
> if you suggest.

Sending a new version while discussions are ongoing is not how we reach
consensus.

Make the driver as part of matrix-keypad driver or bring real arguments
why it cannot be merged.

Best regards,
Krzysztof
Gireesh.Hiremath@in.bosch.com May 10, 2022, 2:13 p.m. UTC | #2
From: Gireesh Hiremath <Gireesh.Hiremath@in.bosch.com>

Hi Krzysztof,

>>>> both matric_keypad.c and mt_matrix_kepad.c logically operate differently,
>>>> my openion is not to merge both.
>>>
>>> IMHO from the user/system-integrator pov it is looking the same and so
>>> one driver should be fine. To distinguish between both modes we could
>>> add dt-property or add a new dt-compatible like "gpio-matrix-keypad-v2".
>>>
>> 
>> as mentioned above our keypad is not complete matrix keypad  and it will
>> not be compatible with matrix_keypad diver. that is the reason we derived
>> mt matrix keypad driver.
>> 
>> to avoid confusion, we will rename the driver as bosch_mt_keypad.c
>> if you suggest.
>
>Sending a new version while discussions are ongoing is not how we reach
>consensus.

I apologize for sending new version.

>
>Make the driver as part of matrix-keypad driver or bring real arguments
>why it cannot be merged.

I tryied to put real hardware scenario which used in 
Bosch Power tool measuring devices.
Keypad schematic as below, it is reduced matrix keypad compared
to standard matrix keypad 

                     Pin8 (gpio1 16)-----------------------
                     Pin7 (gpio1 20)--------------------- |
                     Pin6 (gpio1 22)------------------- | |
                     Pin5 (gpio2 21)----------------- | | |
                     Pin4 (ground  )--------------- | | | |
                     Pin3 (gpio1 31)------------- | | | | |
                     Pin2 (gpio1 23)----------- | | | | | |
                     Pin1 (gpio1 24)--------- | | | | | | |
                                            | | | | | | | |
                                            | | | | | | | |
                                            | | | | | | | |
    |------------|---------|----------------- | | | | | | |-----------|
    |  Button1   |         |  Button2         | | | | | |    Button3  | 
    |      _|_   |         |   _|_            | | | | | |       _|_   | 
    |  |--o   o--|         |--o   o-----------| | | | | |------o   o--|       
    |  |                                      | | | | | |             |
    |  |         |----------------------------| | | | | |             |
    |  | Button4 |            Button5           | | | | |  Button6    |
    |  |   _|_   |              _|_             | | | | |    _|_      |
    |  |--o   o--|         |---o   o------------| | | | |---o   o-----|
    |  |                   |                      | | |               |
    |  |                   |------------------|---| | |-----------|   |
    |  |                                      |     |             |   |
    |  |------------------------------|       |     |---------|   |   |
    |                                 |       |               |   |   |
    |   Button7              Button8  |	      |    Button9    |   |   |
    |      _|_                _|_     |	      |       _|_     |   |   |
    |-----o   o-----|--------o   o----|       |------o   o----|   |   |
                    |                 |                           |   |
                    |                 |---------------------------|   |
                    |                                                 |
                    |-------------------------------------------------|


    ____________________________________
    | Button  | Pin activation| Keymap |
    |----------------------------------|
    |Button1  |	    1,6       | KEY_7  |
    |----------------------------------|
    |Button2  |	    1,2       | KEY_8  |
    |----------------------------------|
    |Button3  |	    7,8       | KEY_9  |
    |----------------------------------|
    |Button4  |	    2,6       | KEY_4  |
    |----------------------------------|
    |Button5  |	    3,4       | KEY_5  |
    |----------------------------------|
    |Button6  |	    6,7       | KEY_6  |
    |----------------------------------|
    |Button7  |	    1,8       | KEY_1  |
    |----------------------------------|
    |Button8  |	    6,8       | KEY_2  |
    |----------------------------------|
    |Button9  |	    4,5       | KEY_3  |
    |----------------------------------|
				
for Button5 and Button9 we used standard gpio_keys.c driver.

Button1,2,3,4,6,7,8 are not in standard row and column format,
found difficulty to apply matrix keypad drive to these button.

to solve this we came with vendor specific driver like
mt_matrix_keypad.c by taking matrix_keypad as reference.

after your review comment I felt it should named as
bosch_keypad.c to show as vendor specific.

in this driver all gpio lines act as row as well as column,
a key can be placed at each intersection of a unique row
number not equal to a unique column and they are diagonally
symmetric.
we can skip keymap for the valid intersection of gpio and
invalid keymap for row equal to column.

the matrix table as below for above schematic

    ------------------------------------------------------
    |Row\Col |GPIO 0 | GPIO 1 | GPIO 2 | GPIO 3 | GPIO 4 |
    ------------------------------------------------------
    | GPIO 0 |  X    | KEY_9  | KEY_2  |   X    | KEY_1  |
    ------------------------------------------------------
    | GPIO 1 | KEY_9 |  X     | KEY_6  |   X    |  X     |
    ------------------------------------------------------
    | GPIO 2 | KEY_2 | KEY_6  |  X     | KEY_4  | KEY_7  |
    ------------------------------------------------------
    | GPIO 3 |  X    |  X     | KEY_4  |  X     | KEY_8  |
    ------------------------------------------------------
    | GPIO 4 | KEY_1 |  X     | KEY_7  | KEY_8  |  X     |
    ------------------------------------------------------
    X - invalid key
    KEY_x - preferred key code


in Device tree we avoided row and column 
and passed gpio info as line-gpios

line-gpios = <
          &gpio1 24 1     /*gpio_56*/
          &gpio1 23 1     /*gpio_55*/
          &gpio1 22 1     /*gpio_54*/
          &gpio1 20 1     /*gpio_52*/
          &gpio1 16 1     /*gpio_48*/
        >;
        linux,keymap = <
                0x00000000 /* row 0, col 0, KEY_RESERVED */
                0x0001000a /* row 0, col 1, KEY_9 */
                0x00020003 /* row 0, col 2, KEY_2 */
                0x00030000 /* row 0, col 3, KEY_RESERVED */
                0x00040002 /* row 0, col 4, KEY_1 */
                0x0100000a /* row 1, col 0, KEY_9 */
                0x01010000 /* row 1, col 1, KEY_RESERVED */
                0x01020007 /* row 1, col 2, KEY_6 */
                0x01030000 /* row 1, col 3, KEY_RESERVED */
                0x01040000 /* row 1, col 4, KEY_RESERVED */
                0x02000003 /* row 2, col 0, KEY_2 */
                0x02010007 /* row 2, col 1, KEY_6 */
                0x02020000 /* row 2, col 2, KEY_RESERVED */
                0x02030005 /* row 2, col 3, KEY_4 */
                0x02040008 /* row 2, col 4, KEY_7 */
                0x03000000 /* row 3, col 0, KEY_RESERVED */
                0x03010000 /* row 3, col 1, KEY_RESERVED */
                0x03020005 /* row 3, col 2, KEY_4 */
                0x03030000 /* row 3, col 3, KEY_RESERVED */
                0x03040009 /* row 3, col 4, KEY_8 */
                0x04000002 /* row 4, col 0, KEY_1 */
                0x04010000 /* row 4, col 1, KEY_RESERVED */
                0x04020008 /* row 4, col 2, KEY_7 */
                0x04030009 /* row 4, col 3, KEY_8 */
                0x04040000 /* row 4, col 4, KEY_RESERVED */
        >;

this driver approch may be usefull for the embadded device
which are using reduced matrix keypad
		
>
>Best regards,
>Krzysztof

Best regards,
Gireesh Hiremath
Krzysztof Kozlowski May 11, 2022, 4:46 p.m. UTC | #3
On 10/05/2022 16:13, Gireesh.Hiremath@in.bosch.com wrote:
> From: Gireesh Hiremath <Gireesh.Hiremath@in.bosch.com>
> 
> Hi Krzysztof,
> 
>>>>> both matric_keypad.c and mt_matrix_kepad.c logically operate differently,
>>>>> my openion is not to merge both.
>>>>
>>>> IMHO from the user/system-integrator pov it is looking the same and so
>>>> one driver should be fine. To distinguish between both modes we could
>>>> add dt-property or add a new dt-compatible like "gpio-matrix-keypad-v2".
>>>>
>>>
>>> as mentioned above our keypad is not complete matrix keypad  and it will
>>> not be compatible with matrix_keypad diver. that is the reason we derived
>>> mt matrix keypad driver.
>>>
>>> to avoid confusion, we will rename the driver as bosch_mt_keypad.c
>>> if you suggest.
>>
>> Sending a new version while discussions are ongoing is not how we reach
>> consensus.
> 
> I apologize for sending new version.
> 
>>
>> Make the driver as part of matrix-keypad driver or bring real arguments
>> why it cannot be merged.
> 
> I tryied to put real hardware scenario which used in 
> Bosch Power tool measuring devices.
> Keypad schematic as below, it is reduced matrix keypad compared
> to standard matrix keypad 
> 
>                      Pin8 (gpio1 16)-----------------------
>                      Pin7 (gpio1 20)--------------------- |
>                      Pin6 (gpio1 22)------------------- | |
>                      Pin5 (gpio2 21)----------------- | | |
>                      Pin4 (ground  )--------------- | | | |
>                      Pin3 (gpio1 31)------------- | | | | |
>                      Pin2 (gpio1 23)----------- | | | | | |
>                      Pin1 (gpio1 24)--------- | | | | | | |
>                                             | | | | | | | |
>                                             | | | | | | | |
>                                             | | | | | | | |
>     |------------|---------|----------------- | | | | | | |-----------|
>     |  Button1   |         |  Button2         | | | | | |    Button3  | 
>     |      _|_   |         |   _|_            | | | | | |       _|_   | 
>     |  |--o   o--|         |--o   o-----------| | | | | |------o   o--|       
>     |  |                                      | | | | | |             |
>     |  |         |----------------------------| | | | | |             |
>     |  | Button4 |            Button5           | | | | |  Button6    |
>     |  |   _|_   |              _|_             | | | | |    _|_      |
>     |  |--o   o--|         |---o   o------------| | | | |---o   o-----|
>     |  |                   |                      | | |               |
>     |  |                   |------------------|---| | |-----------|   |
>     |  |                                      |     |             |   |
>     |  |------------------------------|       |     |---------|   |   |
>     |                                 |       |               |   |   |
>     |   Button7              Button8  |	      |    Button9    |   |   |
>     |      _|_                _|_     |	      |       _|_     |   |   |
>     |-----o   o-----|--------o   o----|       |------o   o----|   |   |
>                     |                 |                           |   |
>                     |                 |---------------------------|   |
>                     |                                                 |
>                     |-------------------------------------------------|
> 
> 
>     ____________________________________
>     | Button  | Pin activation| Keymap |
>     |----------------------------------|
>     |Button1  |	    1,6       | KEY_7  |
>     |----------------------------------|
>     |Button2  |	    1,2       | KEY_8  |
>     |----------------------------------|
>     |Button3  |	    7,8       | KEY_9  |
>     |----------------------------------|
>     |Button4  |	    2,6       | KEY_4  |
>     |----------------------------------|
>     |Button5  |	    3,4       | KEY_5  |
>     |----------------------------------|
>     |Button6  |	    6,7       | KEY_6  |
>     |----------------------------------|
>     |Button7  |	    1,8       | KEY_1  |
>     |----------------------------------|
>     |Button8  |	    6,8       | KEY_2  |
>     |----------------------------------|
>     |Button9  |	    4,5       | KEY_3  |
>     |----------------------------------|
> 				
> for Button5 and Button9 we used standard gpio_keys.c driver.
> 
> Button1,2,3,4,6,7,8 are not in standard row and column format,
> found difficulty to apply matrix keypad drive to these button.
> 
> to solve this we came with vendor specific driver like
> mt_matrix_keypad.c by taking matrix_keypad as reference.
> 
> after your review comment I felt it should named as
> bosch_keypad.c to show as vendor specific.
> 
> in this driver all gpio lines act as row as well as column,
> a key can be placed at each intersection of a unique row
> number not equal to a unique column and they are diagonally
> symmetric.
> we can skip keymap for the valid intersection of gpio and
> invalid keymap for row equal to column.
> 
> the matrix table as below for above schematic
> 
>     ------------------------------------------------------
>     |Row\Col |GPIO 0 | GPIO 1 | GPIO 2 | GPIO 3 | GPIO 4 |
>     ------------------------------------------------------
>     | GPIO 0 |  X    | KEY_9  | KEY_2  |   X    | KEY_1  |
>     ------------------------------------------------------
>     | GPIO 1 | KEY_9 |  X     | KEY_6  |   X    |  X     |
>     ------------------------------------------------------
>     | GPIO 2 | KEY_2 | KEY_6  |  X     | KEY_4  | KEY_7  |
>     ------------------------------------------------------
>     | GPIO 3 |  X    |  X     | KEY_4  |  X     | KEY_8  |
>     ------------------------------------------------------
>     | GPIO 4 | KEY_1 |  X     | KEY_7  | KEY_8  |  X     |
>     ------------------------------------------------------
>     X - invalid key
>     KEY_x - preferred key code
> 
> 
> in Device tree we avoided row and column 
> and passed gpio info as line-gpios
> 
> line-gpios = <
>           &gpio1 24 1     /*gpio_56*/
>           &gpio1 23 1     /*gpio_55*/
>           &gpio1 22 1     /*gpio_54*/
>           &gpio1 20 1     /*gpio_52*/
>           &gpio1 16 1     /*gpio_48*/
>         >;
>         linux,keymap = <
>                 0x00000000 /* row 0, col 0, KEY_RESERVED */
>                 0x0001000a /* row 0, col 1, KEY_9 */
>                 0x00020003 /* row 0, col 2, KEY_2 */
>                 0x00030000 /* row 0, col 3, KEY_RESERVED */
>                 0x00040002 /* row 0, col 4, KEY_1 */
>                 0x0100000a /* row 1, col 0, KEY_9 */
>                 0x01010000 /* row 1, col 1, KEY_RESERVED */
>                 0x01020007 /* row 1, col 2, KEY_6 */
>                 0x01030000 /* row 1, col 3, KEY_RESERVED */
>                 0x01040000 /* row 1, col 4, KEY_RESERVED */
>                 0x02000003 /* row 2, col 0, KEY_2 */
>                 0x02010007 /* row 2, col 1, KEY_6 */
>                 0x02020000 /* row 2, col 2, KEY_RESERVED */
>                 0x02030005 /* row 2, col 3, KEY_4 */
>                 0x02040008 /* row 2, col 4, KEY_7 */
>                 0x03000000 /* row 3, col 0, KEY_RESERVED */
>                 0x03010000 /* row 3, col 1, KEY_RESERVED */
>                 0x03020005 /* row 3, col 2, KEY_4 */
>                 0x03030000 /* row 3, col 3, KEY_RESERVED */
>                 0x03040009 /* row 3, col 4, KEY_8 */
>                 0x04000002 /* row 4, col 0, KEY_1 */
>                 0x04010000 /* row 4, col 1, KEY_RESERVED */
>                 0x04020008 /* row 4, col 2, KEY_7 */
>                 0x04030009 /* row 4, col 3, KEY_8 */
>                 0x04040000 /* row 4, col 4, KEY_RESERVED */
>         >;
> 
> this driver approch may be usefull for the embadded device
> which are using reduced matrix keypad

You wrote pretty long message explaining how the device works, but I
still do not see the answer to questions - why it cannot be part of
matrix keypad?

"It looks like this driver has smaller number of features than
matrix-keypad, so it should be integrated into the matrix-keypad.
matrix-keypad features are superset to this one."

"But anyway this should be just merged into matrix-keypad. It's a
simpler set of that binding."


Best regards,
Krzysztof
kernel test robot May 12, 2022, 4:43 a.m. UTC | #4
Hi,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on tmlind-omap/for-next]
[also build test WARNING on next-20220511]
[cannot apply to dtor-input/next robh/for-next balbi-usb/testing/next v5.18-rc6]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/intel-lab-lkp/linux/commits/Gireesh-Hiremath-in-bosch-com/ARM-dts-am335x-Guardian-switch-to-AM33XX_PADCONF-pinmux-macro/20220506-153118
base:   https://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap.git for-next
config: riscv-randconfig-c006-20220508 (https://download.01.org/0day-ci/archive/20220512/202205121241.RQJCa61u-lkp@intel.com/config)
compiler: clang version 15.0.0 (https://github.com/llvm/llvm-project af4cf1c6b8ed0d8102fc5e69acdc2fcbbcdaa9a7)
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # install riscv cross compiling tool for clang build
        # apt-get install binutils-riscv64-linux-gnu
        # https://github.com/intel-lab-lkp/linux/commit/eb3dca58cf317366877720c44e785ab0ce151ef8
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Gireesh-Hiremath-in-bosch-com/ARM-dts-am335x-Guardian-switch-to-AM33XX_PADCONF-pinmux-macro/20220506-153118
        git checkout eb3dca58cf317366877720c44e785ab0ce151ef8
        # save the config file
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross ARCH=riscv clang-analyzer 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

>> drivers/input/keyboard/mt_matrix_keypad.c:200:7: warning: variable 'any_btn_served' set but not used [-Wunused-but-set-variable]
           bool any_btn_served = false;
                ^
   1 warning generated.


clang-analyzer warnings: (new ones prefixed by >>)
                  ^~~~~~~
   drivers/hwmon/w83627ehf.c:991:1: warning: Call to function 'sprintf' is insecure as it does not provide security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'sprintf_s' in case of C11 [clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling]
   fan_functions(fan_step_output, data->REG_FAN_STEP_OUTPUT)
   ^
   drivers/hwmon/w83627ehf.c:965:9: note: expanded from macro 'fan_functions'
           return sprintf(buf, "%d\n", data->reg[nr]); \
                  ^~~~~~~
   drivers/hwmon/w83627ehf.c:991:1: note: Call to function 'sprintf' is insecure as it does not provide security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'sprintf_s' in case of C11
   fan_functions(fan_step_output, data->REG_FAN_STEP_OUTPUT)
   ^
   drivers/hwmon/w83627ehf.c:965:9: note: expanded from macro 'fan_functions'
           return sprintf(buf, "%d\n", data->reg[nr]); \
                  ^~~~~~~
   drivers/hwmon/w83627ehf.c:1027:1: warning: Call to function 'sprintf' is insecure as it does not provide security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'sprintf_s' in case of C11 [clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling]
   fan_time_functions(fan_stop_time, W83627EHF_REG_FAN_STOP_TIME)
   ^
   drivers/hwmon/w83627ehf.c:1001:9: note: expanded from macro 'fan_time_functions'
           return sprintf(buf, "%d\n", \
                  ^~~~~~~
   drivers/hwmon/w83627ehf.c:1027:1: note: Call to function 'sprintf' is insecure as it does not provide security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'sprintf_s' in case of C11
   fan_time_functions(fan_stop_time, W83627EHF_REG_FAN_STOP_TIME)
   ^
   drivers/hwmon/w83627ehf.c:1001:9: note: expanded from macro 'fan_time_functions'
           return sprintf(buf, "%d\n", \
                  ^~~~~~~
   drivers/hwmon/w83627ehf.c:1082:9: warning: Call to function 'sprintf' is insecure as it does not provide security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'sprintf_s' in case of C11 [clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling]
           return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
                  ^~~~~~~
   drivers/hwmon/w83627ehf.c:1082:9: note: Call to function 'sprintf' is insecure as it does not provide security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'sprintf_s' in case of C11
           return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
                  ^~~~~~~
   Suppressed 29 warnings (29 in non-user code).
   Use -header-filter=.* to display errors from all non-system headers. Use -system-headers to display errors from system headers as well.
   40 warnings generated.
   Suppressed 40 warnings (40 in non-user code).
   Use -header-filter=.* to display errors from all non-system headers. Use -system-headers to display errors from system headers as well.
   53 warnings generated.
   drivers/leds/leds-lp3952.c:104:2: warning: Call to function 'strncpy' is insecure as it does not provide security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'strncpy_s' in case of C11 [clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling]
           strncpy(dest, str, LP3952_LABEL_MAX_LEN);
           ^~~~~~~
   drivers/leds/leds-lp3952.c:104:2: note: Call to function 'strncpy' is insecure as it does not provide security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'strncpy_s' in case of C11
           strncpy(dest, str, LP3952_LABEL_MAX_LEN);
           ^~~~~~~
   Suppressed 52 warnings (52 in non-user code).
   Use -header-filter=.* to display errors from all non-system headers. Use -system-headers to display errors from system headers as well.
   59 warnings generated.
   drivers/leds/leds-lp5521.c:230:9: warning: Call to function 'sscanf' is insecure as it does not provide security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'sscanf_s' in case of C11 [clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling]
                   ret = sscanf(data + offset, "%2s%n ", c, &nrchars);
                         ^~~~~~
   drivers/leds/leds-lp5521.c:230:9: note: Call to function 'sscanf' is insecure as it does not provide security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'sscanf_s' in case of C11
                   ret = sscanf(data + offset, "%2s%n ", c, &nrchars);
                         ^~~~~~
   drivers/leds/leds-lp5521.c:234:9: warning: Call to function 'sscanf' is insecure as it does not provide security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'sscanf_s' in case of C11 [clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling]
                   ret = sscanf(c, "%2x", &cmd);
                         ^~~~~~
   drivers/leds/leds-lp5521.c:234:9: note: Call to function 'sscanf' is insecure as it does not provide security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'sscanf_s' in case of C11
                   ret = sscanf(c, "%2x", &cmd);
                         ^~~~~~
   drivers/leds/leds-lp5521.c:306:2: warning: Value stored to 'ret' is never read [clang-analyzer-deadcode.DeadStores]
           ret = lp55xx_write(chip, LP5521_REG_OP_MODE, LP5521_CMD_DIRECT);
           ^     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/leds/leds-lp5521.c:306:2: note: Value stored to 'ret' is never read
           ret = lp55xx_write(chip, LP5521_REG_OP_MODE, LP5521_CMD_DIRECT);
           ^     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/leds/leds-lp5521.c:368:2: warning: Undefined or garbage value returned to caller [clang-analyzer-core.uninitialized.UndefReturn]
           return ret;
           ^      ~~~
   drivers/leds/leds-lp5521.c:355:2: note: 'ret' declared without an initial value
           int ret;
           ^~~~~~~
   drivers/leds/leds-lp5521.c:359:14: note: Assuming 'i' is >= field 'num_colors'
           for (i = 0; i < led->mc_cdev.num_colors; i++) {
                       ^~~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/leds/leds-lp5521.c:359:2: note: Loop condition is false. Execution continues on line 367
           for (i = 0; i < led->mc_cdev.num_colors; i++) {
           ^
   drivers/leds/leds-lp5521.c:368:2: note: Undefined or garbage value returned to caller
           return ret;
           ^      ~~~
   drivers/leds/leds-lp5521.c:394:10: warning: Call to function 'sprintf' is insecure as it does not provide security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'sprintf_s' in case of C11 [clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling]
                   return sprintf(buf, "run\n");
                          ^~~~~~~
   drivers/leds/leds-lp5521.c:394:10: note: Call to function 'sprintf' is insecure as it does not provide security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'sprintf_s' in case of C11
                   return sprintf(buf, "run\n");
                          ^~~~~~~
   drivers/leds/leds-lp5521.c:396:10: warning: Call to function 'sprintf' is insecure as it does not provide security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'sprintf_s' in case of C11 [clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling]
                   return sprintf(buf, "load\n");
                          ^~~~~~~
   drivers/leds/leds-lp5521.c:396:10: note: Call to function 'sprintf' is insecure as it does not provide security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'sprintf_s' in case of C11
                   return sprintf(buf, "load\n");
                          ^~~~~~~
   drivers/leds/leds-lp5521.c:399:10: warning: Call to function 'sprintf' is insecure as it does not provide security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'sprintf_s' in case of C11 [clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling]
                   return sprintf(buf, "disabled\n");
                          ^~~~~~~
   drivers/leds/leds-lp5521.c:399:10: note: Call to function 'sprintf' is insecure as it does not provide security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'sprintf_s' in case of C11
                   return sprintf(buf, "disabled\n");
                          ^~~~~~~
   Suppressed 52 warnings (52 in non-user code).
   Use -header-filter=.* to display errors from all non-system headers. Use -system-headers to display errors from system headers as well.
   43 warnings generated.
>> drivers/input/keyboard/mt_matrix_keypad.c:297:35: warning: Division by zero [clang-analyzer-core.DivideZero]
                           pdata, (int)(pdata->scan_phase % pdata->num_line_gpios),
                                                          ^
   drivers/input/keyboard/mt_matrix_keypad.c:346:6: note: Assuming field 'stopped' is equal to false
           if (keypad->stopped == false) {
               ^~~~~~~~~~~~~~~~~~~~~~~~
   drivers/input/keyboard/mt_matrix_keypad.c:346:2: note: Taking true branch
           if (keypad->stopped == false) {
           ^
   drivers/input/keyboard/mt_matrix_keypad.c:347:3: note: Calling 'update_buttons'
                   update_buttons(pdata, input_dev);
                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/input/keyboard/mt_matrix_keypad.c:222:6: note: Assuming field 'scan_phase' is not equal to field 'phase_prepare'
           if (pdata->scan_phase == pdata->phase_state.phase_prepare) {
               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/input/keyboard/mt_matrix_keypad.c:222:2: note: Taking false branch
           if (pdata->scan_phase == pdata->phase_state.phase_prepare) {
           ^
   drivers/input/keyboard/mt_matrix_keypad.c:225:13: note: Assuming field 'scan_phase' is not equal to field 'phase_update_button'
           } else if (pdata->scan_phase ==
                      ^~~~~~~~~~~~~~~~~~~~
   drivers/input/keyboard/mt_matrix_keypad.c:225:9: note: Taking false branch
           } else if (pdata->scan_phase ==
                  ^
   drivers/input/keyboard/mt_matrix_keypad.c:266:15: note: Assuming 'i' is >= field 'num_line_gpios'
                   for (i = 0; i < pdata->num_line_gpios; i++) {
                               ^~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/input/keyboard/mt_matrix_keypad.c:266:3: note: Loop condition is false. Execution continues on line 277
                   for (i = 0; i < pdata->num_line_gpios; i++) {
                   ^
   drivers/input/keyboard/mt_matrix_keypad.c:277:7: note: 'number_of_buttons_pressed' is < 2
                   if (number_of_buttons_pressed < 2) {
                       ^~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/input/keyboard/mt_matrix_keypad.c:277:3: note: Taking true branch
                   if (number_of_buttons_pressed < 2) {
                   ^
   drivers/input/keyboard/mt_matrix_keypad.c:278:4: note: Loop condition is false. Execution continues on line 293
                           for (i = 0; i < pdata->num_line_gpios; i++) {
                           ^
   drivers/input/keyboard/mt_matrix_keypad.c:297:35: note: Division by zero
                           pdata, (int)(pdata->scan_phase % pdata->num_line_gpios),
                                        ~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~
>> drivers/input/keyboard/mt_matrix_keypad.c:488:2: warning: Value stored to 'i' is never read [clang-analyzer-deadcode.DeadStores]
           i = pdata->num_line_gpios;
           ^   ~~~~~~~~~~~~~~~~~~~~~
   drivers/input/keyboard/mt_matrix_keypad.c:488:2: note: Value stored to 'i' is never read
           i = pdata->num_line_gpios;
           ^   ~~~~~~~~~~~~~~~~~~~~~
   Suppressed 41 warnings (40 in non-user code, 1 with check filters).
   Use -header-filter=.* to display errors from all non-system headers. Use -system-headers to display errors from system headers as well.
   40 warnings generated.
   Suppressed 40 warnings (40 in non-user code).
   Use -header-filter=.* to display errors from all non-system headers. Use -system-headers to display errors from system headers as well.
   52 warnings generated.
   Suppressed 52 warnings (52 in non-user code).
   Use -header-filter=.* to display errors from all non-system headers. Use -system-headers to display errors from system headers as well.
   64 warnings generated.
   drivers/media/dvb-frontends/cxd2841er.c:236:2: warning: Call to function 'memcpy' is insecure as it does not provide security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'memcpy_s' in case of C11 [clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling]
           memcpy(&buf[1], data, len);
           ^
   include/linux/fortify-string.h:369:26: note: expanded from macro 'memcpy'
   #define memcpy(p, q, s)  __fortify_memcpy_chk(p, q, s,                  \
                            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/fortify-string.h:362:2: note: expanded from macro '__fortify_memcpy_chk'
           __underlying_##op(p, q, __fortify_size);                        \
           ^~~~~~~~~~~~~~~~~
   note: expanded from here
   include/linux/fortify-string.h:45:29: note: expanded from macro '__underlying_memcpy'
   #define __underlying_memcpy     __builtin_memcpy
                                   ^~~~~~~~~~~~~~~~
   drivers/media/dvb-frontends/cxd2841er.c:236:2: note: Call to function 'memcpy' is insecure as it does not provide security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'memcpy_s' in case of C11
           memcpy(&buf[1], data, len);
           ^
   include/linux/fortify-string.h:369:26: note: expanded from macro 'memcpy'
   #define memcpy(p, q, s)  __fortify_memcpy_chk(p, q, s,                  \
                            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/fortify-string.h:362:2: note: expanded from macro '__fortify_memcpy_chk'
           __underlying_##op(p, q, __fortify_size);                        \
           ^~~~~~~~~~~~~~~~~
   note: expanded from here
   include/linux/fortify-string.h:45:29: note: expanded from macro '__underlying_memcpy'
   #define __underlying_memcpy     __builtin_memcpy
                                   ^~~~~~~~~~~~~~~~
   drivers/media/dvb-frontends/cxd2841er.c:3600:25: warning: Value stored to 'priv' during its initialization is never read [clang-analyzer-deadcode.DeadStores]
           struct cxd2841er_priv *priv = fe->demodulator_priv;
                                  ^~~~   ~~~~~~~~~~~~~~~~~~~~
   drivers/media/dvb-frontends/cxd2841er.c:3600:25: note: Value stored to 'priv' during its initialization is never read
           struct cxd2841er_priv *priv = fe->demodulator_priv;
                                  ^~~~   ~~~~~~~~~~~~~~~~~~~~
   drivers/media/dvb-frontends/cxd2841er.c:3714:2: warning: Call to function 'memset' is insecure as it does not provide security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'memset_s' in case of C11 [clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling]
           memset(data, 0, sizeof(data));
           ^
   include/linux/fortify-string.h:272:25: note: expanded from macro 'memset'
   #define memset(p, c, s) __fortify_memset_chk(p, c, s,                   \
                           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/fortify-string.h:265:2: note: expanded from macro '__fortify_memset_chk'
           __underlying_memset(p, c, __fortify_size);                      \
           ^~~~~~~~~~~~~~~~~~~
   include/linux/fortify-string.h:47:29: note: expanded from macro '__underlying_memset'
   #define __underlying_memset     __builtin_memset
                                   ^~~~~~~~~~~~~~~~
   drivers/media/dvb-frontends/cxd2841er.c:3714:2: note: Call to function 'memset' is insecure as it does not provide security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'memset_s' in case of C11
           memset(data, 0, sizeof(data));
           ^
   include/linux/fortify-string.h:272:25: note: expanded from macro 'memset'
   #define memset(p, c, s) __fortify_memset_chk(p, c, s,                   \
                           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/fortify-string.h:265:2: note: expanded from macro '__fortify_memset_chk'
           __underlying_memset(p, c, __fortify_size);                      \
           ^~~~~~~~~~~~~~~~~~~
   include/linux/fortify-string.h:47:29: note: expanded from macro '__underlying_memset'
   #define __underlying_memset     __builtin_memset
                                   ^~~~~~~~~~~~~~~~
   drivers/media/dvb-frontends/cxd2841er.c:3759:25: warning: Value stored to 'priv' during its initialization is never read [clang-analyzer-deadcode.DeadStores]
           struct cxd2841er_priv *priv = fe->demodulator_priv;
                                  ^~~~   ~~~~~~~~~~~~~~~~~~~~
   drivers/media/dvb-frontends/cxd2841er.c:3759:25: note: Value stored to 'priv' during its initialization is never read
           struct cxd2841er_priv *priv = fe->demodulator_priv;
                                  ^~~~   ~~~~~~~~~~~~~~~~~~~~
   drivers/media/dvb-frontends/cxd2841er.c:3812:34: warning: Value stored to 'p' during its initialization is never read [clang-analyzer-deadcode.DeadStores]
           struct dtv_frontend_properties *p = &fe->dtv_property_cache;
                                           ^   ~~~~~~~~~~~~~~~~~~~~~~~
   drivers/media/dvb-frontends/cxd2841er.c:3812:34: note: Value stored to 'p' during its initialization is never read
           struct dtv_frontend_properties *p = &fe->dtv_property_cache;
                                           ^   ~~~~~~~~~~~~~~~~~~~~~~~
   drivers/media/dvb-frontends/cxd2841er.c:3867:3: warning: Call to function 'snprintf' is insecure as it does not provide security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'snprintf_s' in case of C11 [clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling]
                   snprintf(cxd2841er_t_c_ops.info.name, 128,
                   ^~~~~~~~
   drivers/media/dvb-frontends/cxd2841er.c:3867:3: note: Call to function 'snprintf' is insecure as it does not provide security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'snprintf_s' in case of C11
                   snprintf(cxd2841er_t_c_ops.info.name, 128,
                   ^~~~~~~~
   drivers/media/dvb-frontends/cxd2841er.c:3873:3: warning: Call to function 'snprintf' is insecure as it does not provide security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'snprintf_s' in case of C11 [clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling]
                   snprintf(cxd2841er_t_c_ops.info.name, 128,
                   ^~~~~~~~
   drivers/media/dvb-frontends/cxd2841er.c:3873:3: note: Call to function 'snprintf' is insecure as it does not provide security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'snprintf_s' in case of C11
                   snprintf(cxd2841er_t_c_ops.info.name, 128,
                   ^~~~~~~~
   drivers/media/dvb-frontends/cxd2841er.c:3882:3: warning: Call to function 'snprintf' is insecure as it does not provide security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'snprintf_s' in case of C11 [clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling]
                   snprintf(cxd2841er_t_c_ops.info.name, 128,
                   ^~~~~~~~
   drivers/media/dvb-frontends/cxd2841er.c:3882:3: note: Call to function 'snprintf' is insecure as it does not provide security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'snprintf_s' in case of C11
                   snprintf(cxd2841er_t_c_ops.info.name, 128,
                   ^~~~~~~~
--
           ^
   drivers/media/i2c/ov5693.c:1404:6: note: Assuming 'ret' is 0
           if (ret)
               ^~~
   drivers/media/i2c/ov5693.c:1404:2: note: Taking false branch
           if (ret)
           ^
   drivers/media/i2c/ov5693.c:1407:2: note: Loop condition is false.  Exiting loop
           mutex_init(&ov5693->lock);
           ^
   include/linux/mutex.h:101:32: note: expanded from macro 'mutex_init'
   #define mutex_init(mutex)                                               \
                                                                           ^
   drivers/media/i2c/ov5693.c:1412:2: note: Taking false branch
           if (IS_ERR(ov5693->clk)) {
           ^
   drivers/media/i2c/ov5693.c:1418:6: note: Assuming 'clk_rate' is equal to OV5693_XVCLK_FREQ
           if (clk_rate != OV5693_XVCLK_FREQ)
               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/media/i2c/ov5693.c:1418:2: note: Taking false branch
           if (clk_rate != OV5693_XVCLK_FREQ)
           ^
   drivers/media/i2c/ov5693.c:1423:6: note: 'ret' is 0
           if (ret)
               ^~~
   drivers/media/i2c/ov5693.c:1423:2: note: Taking false branch
           if (ret)
           ^
   drivers/media/i2c/ov5693.c:1427:6: note: Assuming 'ret' is 0
           if (ret)
               ^~~
   drivers/media/i2c/ov5693.c:1427:2: note: Taking false branch
           if (ret)
           ^
   drivers/media/i2c/ov5693.c:1440:6: note: 'ret' is 0
           if (ret)
               ^~~
   drivers/media/i2c/ov5693.c:1440:2: note: Taking false branch
           if (ret)
           ^
   drivers/media/i2c/ov5693.c:1444:6: note: Assuming 'ret' is 0
           if (ret)
               ^~~
   drivers/media/i2c/ov5693.c:1444:2: note: Taking false branch
           if (ret)
           ^
   drivers/media/i2c/ov5693.c:1455:6: note: 'ret' is 0
           if (ret)
               ^~~
   drivers/media/i2c/ov5693.c:1455:2: note: Taking false branch
           if (ret)
           ^
   drivers/media/i2c/ov5693.c:1458:8: note: Calling 'ov5693_detect'
           ret = ov5693_detect(ov5693);
                 ^~~~~~~~~~~~~~~~~~~~~
   drivers/media/i2c/ov5693.c:871:2: note: 'id' declared without an initial value
           u32 id;
           ^~~~~~
   drivers/media/i2c/ov5693.c:873:8: note: Calling 'ov5693_read_reg'
           ret = ov5693_read_reg(ov5693, OV5693_REG_CHIP_ID, &id);
                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/media/i2c/ov5693.c:399:8: note: '?' condition is false
           reg = cpu_to_be16(addr & OV5693_REG_ADDR_MASK);
                 ^
   include/linux/byteorder/generic.h:96:21: note: expanded from macro 'cpu_to_be16'
   #define cpu_to_be16 __cpu_to_be16
                       ^
   include/uapi/linux/byteorder/little_endian.h:42:43: note: expanded from macro '__cpu_to_be16'
   #define __cpu_to_be16(x) ((__force __be16)__swab16((x)))
                                             ^
   include/uapi/linux/swab.h:105:3: note: expanded from macro '__swab16'
           (__builtin_constant_p((__u16)(x)) ?     \
            ^
   drivers/media/i2c/ov5693.c:404:6: note: Assuming 'ret' is < 0
           if (ret < 0)
               ^~~~~~~
   drivers/media/i2c/ov5693.c:404:2: note: Taking true branch
           if (ret < 0)
           ^
   drivers/media/i2c/ov5693.c:405:3: note: Returning without writing to '*value'
                   return dev_err_probe(&client->dev, ret,
                   ^
   drivers/media/i2c/ov5693.c:405:3: note: Returning value, which participates in a condition later
                   return dev_err_probe(&client->dev, ret,
                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/media/i2c/ov5693.c:873:8: note: Returning from 'ov5693_read_reg'
           ret = ov5693_read_reg(ov5693, OV5693_REG_CHIP_ID, &id);
                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/media/i2c/ov5693.c:874:6: note: Assuming 'ret' is 0
           if (ret)
               ^~~
   drivers/media/i2c/ov5693.c:874:2: note: Taking false branch
           if (ret)
           ^
   drivers/media/i2c/ov5693.c:877:9: note: The left operand of '!=' is a garbage value
           if (id != OV5693_CHIP_ID)
               ~~ ^
   Suppressed 53 warnings (53 in non-user code).
   Use -header-filter=.* to display errors from all non-system headers. Use -system-headers to display errors from system headers as well.
   43 warnings generated.
>> drivers/input/keyboard/mt_matrix_keypad.c:297:35: warning: Division by zero [clang-analyzer-core.DivideZero]
                           pdata, (int)(pdata->scan_phase % pdata->num_line_gpios),
                                                          ^
   drivers/input/keyboard/mt_matrix_keypad.c:346:6: note: Assuming field 'stopped' is equal to false
           if (keypad->stopped == false) {
               ^~~~~~~~~~~~~~~~~~~~~~~~
   drivers/input/keyboard/mt_matrix_keypad.c:346:2: note: Taking true branch
           if (keypad->stopped == false) {
           ^
   drivers/input/keyboard/mt_matrix_keypad.c:347:3: note: Calling 'update_buttons'
                   update_buttons(pdata, input_dev);
                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/input/keyboard/mt_matrix_keypad.c:222:6: note: Assuming field 'scan_phase' is not equal to field 'phase_prepare'
           if (pdata->scan_phase == pdata->phase_state.phase_prepare) {
               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/input/keyboard/mt_matrix_keypad.c:222:2: note: Taking false branch
           if (pdata->scan_phase == pdata->phase_state.phase_prepare) {
           ^
   drivers/input/keyboard/mt_matrix_keypad.c:225:13: note: Assuming field 'scan_phase' is not equal to field 'phase_update_button'
           } else if (pdata->scan_phase ==
                      ^~~~~~~~~~~~~~~~~~~~
   drivers/input/keyboard/mt_matrix_keypad.c:225:9: note: Taking false branch
           } else if (pdata->scan_phase ==
                  ^
   drivers/input/keyboard/mt_matrix_keypad.c:266:15: note: Assuming 'i' is >= field 'num_line_gpios'
                   for (i = 0; i < pdata->num_line_gpios; i++) {
                               ^~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/input/keyboard/mt_matrix_keypad.c:266:3: note: Loop condition is false. Execution continues on line 277
                   for (i = 0; i < pdata->num_line_gpios; i++) {
                   ^
   drivers/input/keyboard/mt_matrix_keypad.c:277:7: note: 'number_of_buttons_pressed' is < 2
                   if (number_of_buttons_pressed < 2) {
                       ^~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/input/keyboard/mt_matrix_keypad.c:277:3: note: Taking true branch
                   if (number_of_buttons_pressed < 2) {
                   ^
   drivers/input/keyboard/mt_matrix_keypad.c:278:4: note: Loop condition is false. Execution continues on line 293
                           for (i = 0; i < pdata->num_line_gpios; i++) {
                           ^
   drivers/input/keyboard/mt_matrix_keypad.c:297:35: note: Division by zero
                           pdata, (int)(pdata->scan_phase % pdata->num_line_gpios),
                                        ~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~
>> drivers/input/keyboard/mt_matrix_keypad.c:488:2: warning: Value stored to 'i' is never read [clang-analyzer-deadcode.DeadStores]
           i = pdata->num_line_gpios;
           ^   ~~~~~~~~~~~~~~~~~~~~~
   drivers/input/keyboard/mt_matrix_keypad.c:488:2: note: Value stored to 'i' is never read
           i = pdata->num_line_gpios;
           ^   ~~~~~~~~~~~~~~~~~~~~~
   Suppressed 41 warnings (40 in non-user code, 1 with check filters).
   Use -header-filter=.* to display errors from all non-system headers. Use -system-headers to display errors from system headers as well.
   40 warnings generated.
   Suppressed 40 warnings (40 in non-user code).
   Use -header-filter=.* to display errors from all non-system headers. Use -system-headers to display errors from system headers as well.
   52 warnings generated.
   Suppressed 52 warnings (52 in non-user code).
   Use -header-filter=.* to display errors from all non-system headers. Use -system-headers to display errors from system headers as well.
   37 warnings generated.
   drivers/leds/uleds.c:150:4: warning: Value stored to 'retval' is never read [clang-analyzer-deadcode.DeadStores]
                           retval = copy_to_user(buffer, &udev->brightness,
                           ^        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/leds/uleds.c:150:4: note: Value stored to 'retval' is never read
                           retval = copy_to_user(buffer, &udev->brightness,
                           ^        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   Suppressed 36 warnings (36 in non-user code).
   Use -header-filter=.* to display errors from all non-system headers. Use -system-headers to display errors from system headers as well.
   53 warnings generated.
   drivers/firmware/google/framebuffer-coreboot.c:54:2: warning: Call to function 'memset' is insecure as it does not provide security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'memset_s' in case of C11 [clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling]
           memset(&res, 0, sizeof(res));
           ^
   include/linux/fortify-string.h:272:25: note: expanded from macro 'memset'
   #define memset(p, c, s) __fortify_memset_chk(p, c, s,                   \
                           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/fortify-string.h:265:2: note: expanded from macro '__fortify_memset_chk'
           __underlying_memset(p, c, __fortify_size);                      \
           ^~~~~~~~~~~~~~~~~~~
   include/linux/fortify-string.h:47:29: note: expanded from macro '__underlying_memset'
   #define __underlying_memset     __builtin_memset
                                   ^~~~~~~~~~~~~~~~
   drivers/firmware/google/framebuffer-coreboot.c:54:2: note: Call to function 'memset' is insecure as it does not provide security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'memset_s' in case of C11
           memset(&res, 0, sizeof(res));
           ^
   include/linux/fortify-string.h:272:25: note: expanded from macro 'memset'
   #define memset(p, c, s) __fortify_memset_chk(p, c, s,                   \
                           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/fortify-string.h:265:2: note: expanded from macro '__fortify_memset_chk'
           __underlying_memset(p, c, __fortify_size);                      \
           ^~~~~~~~~~~~~~~~~~~
   include/linux/fortify-string.h:47:29: note: expanded from macro '__underlying_memset'
   #define __underlying_memset     __builtin_memset
                                   ^~~~~~~~~~~~~~~~
   Suppressed 52 warnings (52 in non-user code).
   Use -header-filter=.* to display errors from all non-system headers. Use -system-headers to display errors from system headers as well.
   86 warnings generated.
   Suppressed 86 warnings (86 in non-user code).
   Use -header-filter=.* to display errors from all non-system headers. Use -system-headers to display errors from system headers as well.
   80 warnings generated.
   Suppressed 80 warnings (80 in non-user code).
   Use -header-filter=.* to display errors from all non-system headers. Use -system-headers to display errors from system headers as well.
   95 warnings generated.
   include/linux/etherdevice.h:128:2: warning: Assigned value is garbage or undefined [clang-analyzer-core.uninitialized.Assign]
           u16 a = *(const u16 *)addr;
           ^
   net/llc/llc_sap.c:425:2: note: Calling 'llc_pdu_decode_da'
           llc_pdu_decode_da(skb, laddr.mac);
           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/net/llc_pdu.h:278:23: note: '?' condition is true
           if (skb->protocol == htons(ETH_P_802_2))
                                ^
   include/linux/byteorder/generic.h:141:18: note: expanded from macro 'htons'
   #define htons(x) ___htons(x)
                    ^
   include/linux/byteorder/generic.h:135:21: note: expanded from macro '___htons'
   #define ___htons(x) __cpu_to_be16(x)
                       ^
   include/uapi/linux/byteorder/little_endian.h:42:43: note: expanded from macro '__cpu_to_be16'
   #define __cpu_to_be16(x) ((__force __be16)__swab16((x)))
                                             ^
   include/uapi/linux/swab.h:105:3: note: expanded from macro '__swab16'
           (__builtin_constant_p((__u16)(x)) ?     \
            ^
   include/net/llc_pdu.h:278:6: note: Assuming the condition is false
           if (skb->protocol == htons(ETH_P_802_2))
               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/net/llc_pdu.h:278:2: note: Taking false branch
           if (skb->protocol == htons(ETH_P_802_2))
           ^
   net/llc/llc_sap.c:425:2: note: Returning from 'llc_pdu_decode_da'
           llc_pdu_decode_da(skb, laddr.mac);
           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   net/llc/llc_sap.c:428:6: note: Calling 'is_multicast_ether_addr'
           if (is_multicast_ether_addr(laddr.mac)) {
               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/etherdevice.h:128:2: note: Assigned value is garbage or undefined
           u16 a = *(const u16 *)addr;
           ^       ~~~~~~~~~~~~~~~~~~
   net/llc/llc_sap.c:77:2: warning: Call to function 'memset' is insecure as it does not provide security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'memset_s' in case of C11 [clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling]
           memset(addr, 0, sizeof(*addr));
           ^
   include/linux/fortify-string.h:272:25: note: expanded from macro 'memset'
   #define memset(p, c, s) __fortify_memset_chk(p, c, s,                   \
                           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/fortify-string.h:265:2: note: expanded from macro '__fortify_memset_chk'
           __underlying_memset(p, c, __fortify_size);                      \

vim +/any_btn_served +200 drivers/input/keyboard/mt_matrix_keypad.c

   195	
   196	void process_button_events(const struct mt_matrix_keypad_platform_data *pdata,
   197				   struct input_dev *input_dev)
   198	{
   199		int btn_index;
 > 200		bool any_btn_served = false;
   201	
   202		for (btn_index = 0; btn_index < pdata->num_of_buttons; btn_index++) {
   203			const union typeEvent beEvent =
   204				get_and_clear_btn_events(pdata, (int)btn_index);
   205	
   206			if (beEvent.status.boGlobalChanged) {
   207				const struct button_states bsState =
   208					get_btn_id_state(pdata, (int)btn_index);
   209	
   210				if (bsState.boEnabled) {
   211					any_btn_served |=
   212						on_button_event(pdata, (int)btn_index,
   213								beEvent, input_dev);
   214				}
   215			}
   216		}
   217	}
   218	
   219	void update_buttons(struct mt_matrix_keypad_platform_data *pdata,
   220			    struct input_dev *input_dev)
   221	{
   222		if (pdata->scan_phase == pdata->phase_state.phase_prepare) {
   223			pdata->scan_phase = pdata->phase_state.phase_start;
   224			activate_line_driving(pdata, (int)pdata->scan_phase, true);
   225		} else if (pdata->scan_phase ==
   226			   pdata->phase_state.phase_update_button) {
   227			bool btn_changes_occured = false;
   228			int btn_index;
   229	
   230			if (pdata->intialize_buttons) {
   231				int i;
   232	
   233				pdata->intialize_buttons = false;
   234	
   235				for (i = 0; i < pdata->num_of_buttons; i++) {
   236					const bool btn_curr_hw_state =
   237						get_button_state(
   238							&pdata->button_array[i])
   239							.boCurrentStateOfHw;
   240					button_init(&pdata->button_array[i],
   241						    btn_curr_hw_state,
   242						    pdata->button_array[i].key);
   243				}
   244			}
   245	
   246			for (btn_index = 0; btn_index < pdata->num_of_buttons;
   247			     btn_index++) {
   248				btn_changes_occured |= check_button_changes(
   249					&pdata->button_array[btn_index]);
   250			}
   251	
   252			if (btn_changes_occured)
   253				process_button_events(pdata, input_dev);
   254	
   255			pdata->scan_phase = pdata->phase_state.phase_start;
   256		} else {
   257			uint8_t *btn_keylines;
   258			uint8_t number_of_buttons_pressed = 0;
   259			uint8_t btn_index;
   260			uint8_t btn_key;
   261			uint16_t index;
   262			int i;
   263	
   264			btn_keylines = kcalloc(pdata->num_line_gpios, sizeof(uint8_t),
   265					       GFP_KERNEL);
   266			for (i = 0; i < pdata->num_line_gpios; i++) {
   267				index = (pdata->scan_phase * pdata->num_line_gpios) + i;
   268				btn_key = pdata->button_matrix[index];
   269				btn_keylines[i] = false;
   270	
   271				if ((btn_key != pdata->button_matrix[0]) &&
   272				    (get_gpio_line_value(pdata, (int)i) != false)) {
   273					btn_keylines[i] = true;
   274					number_of_buttons_pressed++;
   275				}
   276			}
   277			if (number_of_buttons_pressed < 2) {
   278				for (i = 0; i < pdata->num_line_gpios; i++) {
   279					index = (pdata->scan_phase *
   280						 pdata->num_line_gpios) +
   281						i;
   282					btn_key = pdata->button_matrix[index];
   283					if (btn_key != pdata->button_matrix[0]) {
   284						btn_index =
   285							get_btn_index(pdata, btn_key);
   286						set_btn_state_by_hw(
   287							&pdata->button_array[btn_index],
   288							btn_keylines[i]);
   289					}
   290				}
   291			}
   292	
   293			kfree(btn_keylines);
   294			activate_line_driving(pdata, (int)pdata->scan_phase, false);
   295			pdata->scan_phase++;
   296			activate_line_driving(
 > 297				pdata, (int)(pdata->scan_phase % pdata->num_line_gpios),
   298				true);
   299		}
   300	}
   301
Gireesh.Hiremath@in.bosch.com June 13, 2022, 8:06 a.m. UTC | #5
From: Gireesh Hiremath <Gireesh.Hiremath@in.bosch.com>

Hi Krzysztof,

>You wrote pretty long message explaining how the device works, but I
>still do not see the answer to questions - why it cannot be part of
>matrix keypad?

Following are the difference between matrix keypad and Bosch keypad
make us to add another keypad driver.

matrix keypad:
	- By hardware schematic, a column GPIO line will intersect only
	  with row GPIO lines, not with the other column GPIO lines
	- so, row and column GPIO property are fixed, because of this
	- key scanning work based on interrupt mode
	- and key press is determined based on setting column as output,
	  row GPIO as input and set interrupt to monitor the changes in state,
	  serve the key pressed in ISR

Bosch keypad:
    - By hardware schematic column GPIO line can intersect with row GPIO line
	  as well as other column GPIO lines
	- so, all GPIO act as row as well as column, because of this
	- key scanning based on polling mode
	- a key pressed is determined by setting one of GPIO line as output and
	  other as input and poll for change in the state of input GPIO lines.
	  Setting one of a GPIO line as output and remaining GPIO lines as input is on
	  round robin bases.
>
>"It looks like this driver has smaller number of features than
>matrix-keypad, so it should be integrated into the matrix-keypad.
>matrix-keypad features are superset to this one."
>
>"But anyway this should be just merged into matrix-keypad. It's a
>simpler set of that binding."

This keypad driver specific to Bosch measuring tool or similar devices.
Please let me know to send latest patch which resolves build warning
and gpiod API support.

Best regards,
Gireesh Hiremath
Marco Felsch June 15, 2022, 8:28 a.m. UTC | #6
Hi,

sry. for jumping in again.

On 22-06-13, Gireesh.Hiremath@in.bosch.com wrote:
> From: Gireesh Hiremath <Gireesh.Hiremath@in.bosch.com>
> 
> Hi Krzysztof,
> 
> >You wrote pretty long message explaining how the device works, but I
> >still do not see the answer to questions - why it cannot be part of
> >matrix keypad?
> 
> Following are the difference between matrix keypad and Bosch keypad
> make us to add another keypad driver.
> 
> matrix keypad:
> 	- By hardware schematic, a column GPIO line will intersect only
> 	  with row GPIO lines, not with the other column GPIO lines
> 	- so, row and column GPIO property are fixed, because of this
> 	- key scanning work based on interrupt mode
> 	- and key press is determined based on setting column as output,
> 	  row GPIO as input and set interrupt to monitor the changes in state,
> 	  serve the key pressed in ISR
> 
> Bosch keypad:
>     - By hardware schematic column GPIO line can intersect with row GPIO line
> 	  as well as other column GPIO lines
> 	- so, all GPIO act as row as well as column, because of this
> 	- key scanning based on polling mode
> 	- a key pressed is determined by setting one of GPIO line as output and
> 	  other as input and poll for change in the state of input GPIO lines.
> 	  Setting one of a GPIO line as output and remaining GPIO lines as input is on
> 	  round robin bases.

Thanks again for listing this here but please get our point, that this
seems like just another 'mode' for the matrix keypad driver which can be
selected by the system integrator.

> >"It looks like this driver has smaller number of features than
> >matrix-keypad, so it should be integrated into the matrix-keypad.
> >matrix-keypad features are superset to this one."
> >
> >"But anyway this should be just merged into matrix-keypad. It's a
> >simpler set of that binding."
> 
> This keypad driver specific to Bosch measuring tool or similar devices.

Once it lands in mainline, it can be used by everyone.

> Please let me know to send latest patch which resolves build warning
> and gpiod API support.

I would really appreciate if you could integrate your work into matrix
keypad driver.

Regards,
  Marco
Krzysztof Kozlowski June 15, 2022, 8:58 p.m. UTC | #7
On 13/06/2022 01:06, Gireesh.Hiremath@in.bosch.com wrote:
> From: Gireesh Hiremath <Gireesh.Hiremath@in.bosch.com>
> 
> Hi Krzysztof,
> 
>> You wrote pretty long message explaining how the device works, but I
>> still do not see the answer to questions - why it cannot be part of
>> matrix keypad?
> 
> Following are the difference between matrix keypad and Bosch keypad
> make us to add another keypad driver.
> 
> matrix keypad:
> 	- By hardware schematic, a column GPIO line will intersect only
> 	  with row GPIO lines, not with the other column GPIO lines
> 	- so, row and column GPIO property are fixed, because of this
> 	- key scanning work based on interrupt mode
> 	- and key press is determined based on setting column as output,
> 	  row GPIO as input and set interrupt to monitor the changes in state,
> 	  serve the key pressed in ISR
> 
> Bosch keypad:
>     - By hardware schematic column GPIO line can intersect with row GPIO line
> 	  as well as other column GPIO lines
> 	- so, all GPIO act as row as well as column, because of this
> 	- key scanning based on polling mode
> 	- a key pressed is determined by setting one of GPIO line as output and
> 	  other as input and poll for change in the state of input GPIO lines.
> 	  Setting one of a GPIO line as output and remaining GPIO lines as input is on
> 	  round robin bases.

Which is still not the answer "why it cannot be part of matrix keypad?".
To me looks similar enough, although maybe not exactly superset of the
other.

>>
>> "It looks like this driver has smaller number of features than
>> matrix-keypad, so it should be integrated into the matrix-keypad.
>> matrix-keypad features are superset to this one."
>>
>> "But anyway this should be just merged into matrix-keypad. It's a
>> simpler set of that binding."
> 
> This keypad driver specific to Bosch measuring tool or similar devices.
> Please let me know to send latest patch which resolves build warning
> and gpiod API support.

That's a poor reason not to merge into existing driver... I am sorry,
but our entire Linux kernel concept is to integrate, not duplicate. If
each of vendors wanted their own feature, we would have unmanageable
monstrosity with millions of drivers doing almost the same...


Best regards,
Krzysztof
Gireesh.Hiremath@in.bosch.com Aug. 19, 2022, 6:56 a.m. UTC | #8
From: Gireesh Hiremath <Gireesh.Hiremath@in.bosch.com>

Hi Krzysztof,

>>> You wrote pretty long message explaining how the device works, but I
>>> still do not see the answer to questions - why it cannot be part of
>>> matrix keypad?
>> 
>> Following are the difference between matrix keypad and Bosch keypad
>> make us to add another keypad driver.
>> 
>> matrix keypad:
>> 	- By hardware schematic, a column GPIO line will intersect only
>> 	  with row GPIO lines, not with the other column GPIO lines
>> 	- so, row and column GPIO property are fixed, because of this
>> 	- key scanning work based on interrupt mode
>> 	- and key press is determined based on setting column as output,
>> 	  row GPIO as input and set interrupt to monitor the changes in state,
>> 	  serve the key pressed in ISR
>> 
>> Bosch keypad:
>>     - By hardware schematic column GPIO line can intersect with row GPIO line
>> 	  as well as other column GPIO lines
>> 	- so, all GPIO act as row as well as column, because of this
>> 	- key scanning based on polling mode
>> 	- a key pressed is determined by setting one of GPIO line as output and
>> 	  other as input and poll for change in the state of input GPIO lines.
>> 	  Setting one of a GPIO line as output and remaining GPIO lines as input is on
>> 	  round robin bases.
>
>Which is still not the answer "why it cannot be part of matrix keypad?".
>To me looks similar enough, although maybe not exactly superset of the
>other.

I have merged the Bosch keypad in to the matrix keypad
and sending version v3 patches to support that.

v3-0001-driver-input-matric-keypad-switch-to-gpiod.patch
v3-0002-driver-input-matric-keypad-add-reduced-matrix-sup.patch
v3-0003-dt-bindings-input-gpio-matrix-keypad-add-reduced-.patch 

>
>>>
>>> "It looks like this driver has smaller number of features than
>>> matrix-keypad, so it should be integrated into the matrix-keypad.
>>> matrix-keypad features are superset to this one."
>>>
>>> "But anyway this should be just merged into matrix-keypad. It's a
>>> simpler set of that binding."
>> 
>> This keypad driver specific to Bosch measuring tool or similar devices.
>> Please let me know to send latest patch which resolves build warning
>> and gpiod API support.
>
>That's a poor reason not to merge into existing driver... I am sorry,
>but our entire Linux kernel concept is to integrate, not duplicate. If
>each of vendors wanted their own feature, we would have unmanageable
>monstrosity with millions of drivers doing almost the same...
>
>
>Best regards,
>Krzysztof
>

Best regards,
Gireesh Hiremath
diff mbox series

Patch

diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index 4ea79db8f134..a55ee8656194 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -303,6 +303,16 @@  config KEYBOARD_MATRIX
 	  To compile this driver as a module, choose M here: the
 	  module will be called matrix_keypad.
 
+config KEYBOARD_MT_MATRIX
+        tristate "GPIO driven MT matrix keypad support"
+        depends on GPIOLIB || COMPILE_TEST
+        help
+	  This driver enable support for GPIO driven
+	  mt matrix keypad.
+
+          To compile this driver as a module, choose M here: the
+          module will be called mt_matrix_keypad.
+
 config KEYBOARD_HIL_OLD
 	tristate "HP HIL keyboard support (simple driver)"
 	depends on GSC || HP300
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index 721936e90290..c7686d338b5d 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -41,6 +41,7 @@  obj-$(CONFIG_KEYBOARD_LOCOMO)		+= locomokbd.o
 obj-$(CONFIG_KEYBOARD_LPC32XX)		+= lpc32xx-keys.o
 obj-$(CONFIG_KEYBOARD_MAPLE)		+= maple_keyb.o
 obj-$(CONFIG_KEYBOARD_MATRIX)		+= matrix_keypad.o
+obj-$(CONFIG_KEYBOARD_MT_MATRIX)	+= mt_matrix_keypad.o
 obj-$(CONFIG_KEYBOARD_MAX7359)		+= max7359_keypad.o
 obj-$(CONFIG_KEYBOARD_MCS)		+= mcs_touchkey.o
 obj-$(CONFIG_KEYBOARD_MPR121)		+= mpr121_touchkey.o
diff --git a/drivers/input/keyboard/mt_matrix_keypad.c b/drivers/input/keyboard/mt_matrix_keypad.c
new file mode 100644
index 000000000000..2664ce3c2653
--- /dev/null
+++ b/drivers/input/keyboard/mt_matrix_keypad.c
@@ -0,0 +1,741 @@ 
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ *  GPIO driven mt matrix keyboard driver
+ *
+ *  Copyright (c) 2008 Marek Vasut <marek.vasut@gmail.com>
+ *  Copyright (c) 2017 vinay <VinayKumar.Shettar@in.bosch.com>
+ *
+ *  Based on matrix_keypad.c
+ *
+ */
+
+#include <linux/stddef.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/jiffies.h>
+#include <linux/module.h>
+#include <linux/gpio.h>
+#include <linux/input/mt_matrix_keypad.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/of_platform.h>
+#include <linux/pinctrl/consumer.h>
+
+#define MODULE_NAME "mt-matrix-keypad"
+
+struct mt_matrix_keypad {
+	struct mt_matrix_keypad_platform_data *pdata;
+	struct input_dev *input_dev;
+
+	DECLARE_BITMAP(disabled_gpios, MATRIX_MAX_ROWS);
+
+	struct delayed_work work;
+	spinlock_t lock;
+	bool scan_pending;
+	bool stopped;
+	bool gpio_all_disabled;
+};
+
+static bool
+get_gpio_line_value(const struct mt_matrix_keypad_platform_data *pdata,
+		    int row);
+static void
+activate_line_driving(const struct mt_matrix_keypad_platform_data *pdata,
+		      int line, bool on);
+
+void init_phase(struct mt_matrix_keypad_platform_data *pdata)
+{
+	pdata->phase_state.phase_prepare = -1;
+	pdata->phase_state.phase_start = 0;
+	pdata->phase_state.phase_update_button = pdata->num_line_gpios;
+}
+
+void button_init(struct button *btn, bool btn_hw_state, int key)
+{
+	btn->state.boPrevious = btn_hw_state;
+	btn->state.boCurrentStateOfHw = btn_hw_state;
+	btn->state.boCurrentStateOfSw = false;
+	btn->state.boCurrent = btn_hw_state;
+	btn->state.boEnabled = true;
+	btn->state.boStateAtInit = btn_hw_state;
+	btn->event.ui8Register = 0;
+	btn->key = key;
+}
+
+struct button_states get_button_state(struct button *btn)
+{
+	return btn->state;
+}
+
+union typeEvent get_and_clear_events(struct button *btn)
+{
+	union typeEvent beTemp = btn->event;
+
+	btn->event.ui8Register = 0;
+
+	return beTemp;
+}
+
+uint8_t get_btn_index(struct mt_matrix_keypad_platform_data *pdata, int btn_key)
+{
+	uint8_t i;
+
+	for (i = 0; i < pdata->num_of_buttons; i++) {
+		if (pdata->button_array[i].key == btn_key)
+			break;
+	}
+	return i;
+}
+
+void set_btn_state_by_hw(struct button *btn, bool boButtonState)
+{
+	btn->state.boCurrentStateOfHw = boButtonState;
+}
+
+bool check_button_changes(struct button *btn)
+{
+	btn->state.boPrevious = btn->state.boCurrent;
+	btn->state.boCurrent =
+		btn->state.boCurrentStateOfHw || btn->state.boCurrentStateOfSw;
+
+	/* Check if Button is pressed */
+	if ((btn->state.boPrevious == false) &&
+	    (btn->state.boCurrent == true)) {
+		btn->event.status.boPressed = true;
+	}
+
+	/* Check if Button is released */
+	else if ((btn->state.boPrevious == true) &&
+		 (btn->state.boCurrent == false)) {
+		btn->event.status.boReleased = true;
+	}
+
+	if (btn->event.ui8Register != 0)
+		btn->event.status.boGlobalChanged = true;
+
+	return btn->event.status.boGlobalChanged;
+}
+
+struct button_states
+get_btn_id_state(const struct mt_matrix_keypad_platform_data *pdata,
+		 int btn_index)
+{
+	if (btn_index < pdata->num_of_buttons)
+		return get_button_state(&pdata->button_array[btn_index]);
+	else
+		return get_button_state(&pdata->button_array[0]);
+}
+
+union typeEvent
+get_and_clear_btn_events(const struct mt_matrix_keypad_platform_data *pdata,
+			 int btn_index)
+{
+	if (btn_index < pdata->num_of_buttons)
+		return get_and_clear_events(&pdata->button_array[btn_index]);
+	else
+		return get_and_clear_events(&pdata->button_array[0]);
+}
+
+void button_hdl_init(struct mt_matrix_keypad_platform_data *pdata)
+{
+	int row, col, index;
+	int i;
+
+	pdata->scan_phase = pdata->phase_state.phase_prepare;
+	pdata->intialize_buttons = true;
+
+	/* Init Button Objects, will be reinited once states are captured */
+	i = 0;
+	for (row = 1; row < pdata->num_line_gpios; row++)
+		for (col = 0; col < row; col++) {
+			index = (row * pdata->num_line_gpios) + col;
+			if (pdata->button_matrix[index] !=
+			    pdata->button_matrix[0]) {
+				if (i < pdata->num_of_buttons) {
+					button_init(
+						&pdata->button_array[i], false,
+						pdata->button_matrix[index]);
+					i++;
+				}
+			}
+		}
+
+	pr_debug("[%s]: %s Done\n", MODULE_NAME, __func__);
+}
+
+bool on_button_event(const struct mt_matrix_keypad_platform_data *pdata,
+		     int btn_index, union typeEvent btn_event,
+		     struct input_dev *input_dev)
+{
+	bool any_btn_served = true;
+	unsigned int key_code = 0;
+	int key_value = 0;
+
+	key_code = pdata->button_array[btn_index].key;
+
+	if (btn_event.status.boPressed) {
+		key_value = 1;
+		pr_debug("[%s]:%d Pressed\n", MODULE_NAME, key_code);
+	}
+
+	if (btn_event.status.boReleased) {
+		key_value = 0;
+		pr_debug("[%s]:%d Released\n", MODULE_NAME, key_code);
+	}
+
+	input_report_key(input_dev, key_code, key_value);
+	input_sync(input_dev);
+	return any_btn_served;
+}
+
+void process_button_events(const struct mt_matrix_keypad_platform_data *pdata,
+			   struct input_dev *input_dev)
+{
+	int btn_index;
+	bool any_btn_served = false;
+
+	for (btn_index = 0; btn_index < pdata->num_of_buttons; btn_index++) {
+		const union typeEvent beEvent =
+			get_and_clear_btn_events(pdata, (int)btn_index);
+
+		if (beEvent.status.boGlobalChanged) {
+			const struct button_states bsState =
+				get_btn_id_state(pdata, (int)btn_index);
+
+			if (bsState.boEnabled) {
+				any_btn_served |=
+					on_button_event(pdata, (int)btn_index,
+							beEvent, input_dev);
+			}
+		}
+	}
+}
+
+void update_buttons(struct mt_matrix_keypad_platform_data *pdata,
+		    struct input_dev *input_dev)
+{
+	if (pdata->scan_phase == pdata->phase_state.phase_prepare) {
+		pdata->scan_phase = pdata->phase_state.phase_start;
+		activate_line_driving(pdata, (int)pdata->scan_phase, true);
+	} else if (pdata->scan_phase ==
+		   pdata->phase_state.phase_update_button) {
+		bool btn_changes_occured = false;
+		int btn_index;
+
+		if (pdata->intialize_buttons) {
+			int i;
+
+			pdata->intialize_buttons = false;
+
+			for (i = 0; i < pdata->num_of_buttons; i++) {
+				const bool btn_curr_hw_state =
+					get_button_state(
+						&pdata->button_array[i])
+						.boCurrentStateOfHw;
+				button_init(&pdata->button_array[i],
+					    btn_curr_hw_state,
+					    pdata->button_array[i].key);
+			}
+		}
+
+		for (btn_index = 0; btn_index < pdata->num_of_buttons;
+		     btn_index++) {
+			btn_changes_occured |= check_button_changes(
+				&pdata->button_array[btn_index]);
+		}
+
+		if (btn_changes_occured)
+			process_button_events(pdata, input_dev);
+
+		pdata->scan_phase = pdata->phase_state.phase_start;
+	} else {
+		uint8_t *btn_keylines;
+		uint8_t number_of_buttons_pressed = 0;
+		uint8_t btn_index;
+		uint8_t btn_key;
+		uint16_t index;
+		int i;
+
+		btn_keylines = kcalloc(pdata->num_line_gpios, sizeof(uint8_t),
+				       GFP_KERNEL);
+		for (i = 0; i < pdata->num_line_gpios; i++) {
+			index = (pdata->scan_phase * pdata->num_line_gpios) + i;
+			btn_key = pdata->button_matrix[index];
+			btn_keylines[i] = false;
+
+			if ((btn_key != pdata->button_matrix[0]) &&
+			    (get_gpio_line_value(pdata, (int)i) != false)) {
+				btn_keylines[i] = true;
+				number_of_buttons_pressed++;
+			}
+		}
+		if (number_of_buttons_pressed < 2) {
+			for (i = 0; i < pdata->num_line_gpios; i++) {
+				index = (pdata->scan_phase *
+					 pdata->num_line_gpios) +
+					i;
+				btn_key = pdata->button_matrix[index];
+				if (btn_key != pdata->button_matrix[0]) {
+					btn_index =
+						get_btn_index(pdata, btn_key);
+					set_btn_state_by_hw(
+						&pdata->button_array[btn_index],
+						btn_keylines[i]);
+				}
+			}
+		}
+
+		kfree(btn_keylines);
+		activate_line_driving(pdata, (int)pdata->scan_phase, false);
+		pdata->scan_phase++;
+		activate_line_driving(
+			pdata, (int)(pdata->scan_phase % pdata->num_line_gpios),
+			true);
+	}
+}
+
+/*
+ * NOTE: normally the GPIO has to be put into HiZ when de-activated to cause
+ * minmal side effect when scanning other columns, here it is configured to
+ * be input, and it should work on most platforms.
+ */
+static void
+__activate_line_driving(const struct mt_matrix_keypad_platform_data *pdata,
+			int line, bool on)
+{
+	bool level_on = pdata->active_low;
+
+	if (on)
+		gpio_direction_output(pdata->line_gpios[line], level_on);
+	else
+		gpio_direction_input(pdata->line_gpios[line]);
+}
+
+static void
+activate_line_driving(const struct mt_matrix_keypad_platform_data *pdata,
+		      int line, bool on)
+{
+	__activate_line_driving(pdata, line, on);
+
+	if (on && pdata->col_scan_delay_us)
+		udelay(pdata->col_scan_delay_us);
+}
+
+static bool
+get_gpio_line_value(const struct mt_matrix_keypad_platform_data *pdata, int row)
+{
+	return gpio_get_value(pdata->line_gpios[row]) ? pdata->active_low :
+							!pdata->active_low;
+}
+
+/*
+ * This gets the keys from keyboard and reports it to input subsystem
+ */
+static void mt_matrix_keypad_scan(struct work_struct *work)
+{
+	struct mt_matrix_keypad *keypad =
+		container_of(work, struct mt_matrix_keypad, work.work);
+	struct input_dev *input_dev = keypad->input_dev;
+	struct mt_matrix_keypad_platform_data *pdata = keypad->pdata;
+
+	if (keypad->stopped == false) {
+		update_buttons(pdata, input_dev);
+		schedule_delayed_work(
+			&keypad->work,
+			msecs_to_jiffies(keypad->pdata->debounce_ms));
+	}
+}
+
+static int mt_matrix_keypad_start(struct input_dev *dev)
+{
+	struct mt_matrix_keypad *keypad = input_get_drvdata(dev);
+
+	keypad->stopped = false;
+	/*
+	 * memory access initiated before the memory barrier
+	 * will be complete before passing the barrier
+	 */
+	mb();
+
+	/*
+	 * Schedule an immediate key scan to capture current key state;
+	 * columns will be activated and IRQs be enabled after the scan.
+	 */
+	schedule_delayed_work(&keypad->work, 0);
+
+	return 0;
+}
+
+static void mt_matrix_keypad_stop(struct input_dev *dev)
+{
+	struct mt_matrix_keypad *keypad = input_get_drvdata(dev);
+
+	keypad->stopped = true;
+	/*
+	 * memory access initiated before the memory barrier
+	 * will be complete before passing the barrier
+	 */
+	mb();
+	cancel_delayed_work_sync(&keypad->work);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static void mt_matrix_keypad_enable_wakeup(struct mt_matrix_keypad *keypad)
+{
+	const struct mt_matrix_keypad_platform_data *pdata = keypad->pdata;
+	unsigned int gpio;
+	int i;
+
+	if (pdata->clustered_irq > 0) {
+		if (enable_irq_wake(pdata->clustered_irq) == 0)
+			keypad->gpio_all_disabled = true;
+	} else {
+		for (i = 0; i < pdata->num_line_gpios; i++) {
+			if (!test_bit(i, keypad->disabled_gpios)) {
+				gpio = pdata->line_gpios[i];
+
+				if (enable_irq_wake(gpio_to_irq(gpio)) == 0)
+					__set_bit(i, keypad->disabled_gpios);
+			}
+		}
+	}
+}
+
+static void mt_matrix_keypad_disable_wakeup(struct mt_matrix_keypad *keypad)
+{
+	const struct mt_matrix_keypad_platform_data *pdata = keypad->pdata;
+	unsigned int gpio;
+	int i;
+
+	if (pdata->clustered_irq > 0) {
+		if (keypad->gpio_all_disabled) {
+			disable_irq_wake(pdata->clustered_irq);
+			keypad->gpio_all_disabled = false;
+		}
+	} else {
+		for (i = 0; i < pdata->num_line_gpios; i++) {
+			if (test_and_clear_bit(i, keypad->disabled_gpios)) {
+				gpio = pdata->line_gpios[i];
+				disable_irq_wake(gpio_to_irq(gpio));
+			}
+		}
+	}
+}
+
+static int mt_matrix_keypad_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct mt_matrix_keypad *keypad = platform_get_drvdata(pdev);
+
+	mt_matrix_keypad_stop(keypad->input_dev);
+
+	if (device_may_wakeup(&pdev->dev))
+		mt_matrix_keypad_enable_wakeup(keypad);
+
+	pinctrl_pm_select_sleep_state(dev);
+
+	return 0;
+}
+
+static int mt_matrix_keypad_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct mt_matrix_keypad *keypad = platform_get_drvdata(pdev);
+
+	if (device_may_wakeup(&pdev->dev))
+		mt_matrix_keypad_disable_wakeup(keypad);
+
+	pinctrl_pm_select_default_state(dev);
+
+	mt_matrix_keypad_start(keypad->input_dev);
+
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(mt_matrix_keypad_pm_ops, mt_matrix_keypad_suspend,
+			 mt_matrix_keypad_resume);
+
+static int mt_matrix_keypad_init_gpio(struct platform_device *pdev,
+				      struct mt_matrix_keypad *keypad)
+{
+	const struct mt_matrix_keypad_platform_data *pdata = keypad->pdata;
+	int i, err;
+
+	for (i = 0; i < pdata->num_line_gpios; i++) {
+		err = gpio_request(pdata->line_gpios[i], "mt_kbd_row");
+		if (err) {
+			dev_err(&pdev->dev,
+				"failed to request GPIO%d for ROW%d\n",
+				pdata->line_gpios[i], i);
+			goto err_free_rows;
+		}
+
+		gpio_direction_input(pdata->line_gpios[i]);
+	}
+
+	return 0;
+
+err_free_rows:
+	while (--i >= 0)
+		gpio_free(pdata->line_gpios[i]);
+
+	i = pdata->num_line_gpios;
+	return err;
+}
+
+static void mt_matrix_keypad_free_gpio(struct mt_matrix_keypad *keypad)
+{
+	const struct mt_matrix_keypad_platform_data *pdata = keypad->pdata;
+	int i;
+
+	for (i = 0; i < pdata->num_line_gpios; i++)
+		gpio_free(pdata->line_gpios[i]);
+}
+
+#ifdef CONFIG_OF
+static struct mt_matrix_keypad_platform_data *
+mt_matrix_keypad_parse_dt(struct device *dev)
+{
+	struct mt_matrix_keypad_platform_data *pdata = NULL;
+	struct device_node *np = dev->of_node;
+	unsigned int *gpios;
+	struct button *button_array;
+	int8_t *button_matrix;
+	uint16_t keycode;
+	uint32_t *ptr;
+	int keymap;
+	int i;
+
+	if (!np) {
+		dev_err(dev, "device lacks DT data\n");
+		return ERR_PTR(-ENODEV);
+	}
+
+	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return ERR_PTR(-ENOMEM);
+
+	pdata->num_line_gpios = of_gpio_named_count(np, "line-gpios");
+	if (pdata->num_line_gpios <= 0) {
+		dev_err(dev, "number of gpio line not specified\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	if (of_get_property(np, "linux,no-autorepeat", NULL))
+		pdata->no_autorepeat = true;
+
+	pdata->wakeup = of_property_read_bool(np, "wakeup-source") ||
+			of_property_read_bool(np, "linux,wakeup"); /* legacy */
+
+	if (of_get_property(np, "gpio-activelow", NULL))
+		pdata->active_low = true;
+
+	of_property_read_u32(np, "debounce-delay-ms", &pdata->debounce_ms);
+	of_property_read_u32(np, "col-scan-delay-us",
+			     &pdata->col_scan_delay_us);
+	of_property_read_u32(np, "number-of-buttons", &pdata->num_of_buttons);
+	if (pdata->num_of_buttons <= 0) {
+		dev_err(dev, "number of button not specified\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	button_array =
+		devm_kzalloc(dev,
+			     sizeof(struct button) * (pdata->num_of_buttons),
+			     GFP_KERNEL);
+	if (!button_array) {
+		dev_err(dev, "could not allocate memory for button array\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	pdata->button_array = button_array;
+
+	gpios = devm_kzalloc(dev,
+			     sizeof(unsigned int) * (pdata->num_line_gpios),
+			     GFP_KERNEL);
+	if (!gpios) {
+		dev_err(dev, "could not allocate memory for gpios\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	for (i = 0; i < pdata->num_line_gpios; i++)
+		gpios[i] = of_get_named_gpio(np, "line-gpios", i);
+
+	pdata->line_gpios = gpios;
+
+	keymap = device_property_count_u32(dev, "linux,keymap");
+	if (keymap <= 0 ||
+	    keymap > (pdata->num_line_gpios * pdata->num_line_gpios)) {
+		dev_err(dev, "linux,keymap property count is more");
+		return ERR_PTR(-ENXIO);
+	}
+
+	ptr = kcalloc(keymap, sizeof(uint32_t), GFP_KERNEL);
+	if (!ptr)
+		return ERR_PTR(-ENOMEM);
+
+	if (device_property_read_u32_array(dev, "linux,keymap", ptr, keymap)) {
+		dev_err(dev, "problem parsing keymap property\n");
+		kfree(ptr);
+		return ERR_PTR(-EINVAL);
+	}
+
+	button_matrix =
+		devm_kzalloc(dev, (keymap * sizeof(int8_t)), GFP_KERNEL);
+	if (!button_matrix) {
+		dev_err(dev, "could not allocate memory for button matrix\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	pdata->button_matrix = button_matrix;
+	for (i = 0; i < keymap; i++) {
+		keycode = KEYCODE(ptr[i]);
+		pdata->button_matrix[i] = keycode;
+	}
+	kfree(ptr);
+
+	return pdata;
+}
+
+#else
+static inline struct mt_matrix_keypad_platform_data *
+mt_matrix_keypad_parse_dt(struct device *dev)
+{
+	dev_err(dev, "no platform data defined\n");
+
+	return ERR_PTR(-EINVAL);
+}
+#endif
+
+static int mt_matrix_keypad_probe(struct platform_device *pdev)
+{
+	struct mt_matrix_keypad_platform_data *pdata;
+	struct mt_matrix_keypad *keypad;
+	struct input_dev *input_dev;
+	int err;
+	int row, col, index;
+
+	dev_info(&pdev->dev, "[%s]: Probe\n", MODULE_NAME);
+	pdata = dev_get_platdata(&pdev->dev);
+
+	if (!pdata) {
+		pdata = mt_matrix_keypad_parse_dt(&pdev->dev);
+		if (IS_ERR(pdata)) {
+			dev_err(&pdev->dev, "Mt platform data not defined\n");
+			return PTR_ERR(pdata);
+		}
+	}
+
+	err = pdata->line_gpios[0];
+	if (err < 0)
+		return dev_err_probe(
+			&pdev->dev, err,
+			"Could not register gpio chip for mt matrix keypad\n");
+
+	keypad = kzalloc(sizeof(struct mt_matrix_keypad), GFP_KERNEL);
+	input_dev = input_allocate_device();
+
+	if (!keypad || !input_dev) {
+		dev_err(&pdev->dev, "[%s]: Allocation Failed\n", MODULE_NAME);
+		err = -ENOMEM;
+		goto err_free_mem;
+	}
+
+	init_phase(pdata);
+	keypad->input_dev = input_dev;
+	keypad->pdata = pdata;
+	keypad->stopped = true;
+	INIT_DELAYED_WORK(&keypad->work, mt_matrix_keypad_scan);
+	spin_lock_init(&keypad->lock);
+
+	input_dev->name = pdev->name;
+	input_dev->id.bustype = BUS_HOST;
+	input_dev->dev.parent = &pdev->dev;
+	input_dev->open = mt_matrix_keypad_start;
+	input_dev->close = mt_matrix_keypad_stop;
+
+	if (!pdata->no_autorepeat)
+		__set_bit(EV_REP, input_dev->evbit);
+
+	input_set_capability(input_dev, EV_MSC, MSC_SCAN);
+
+	for (row = 1; row < pdata->num_line_gpios; row++) {
+		for (col = 0; col < row; col++) {
+			index = (row * pdata->num_line_gpios) + col;
+			if (pdata->button_matrix[index] !=
+			    pdata->button_matrix[0]) {
+				input_set_capability(
+					input_dev, EV_KEY,
+					pdata->button_matrix[index]);
+			}
+		}
+	}
+
+	input_set_drvdata(input_dev, keypad);
+	err = mt_matrix_keypad_init_gpio(pdev, keypad);
+
+	if (err)
+		goto err_free_mem;
+
+	button_hdl_init(pdata);
+
+	err = input_register_device(keypad->input_dev);
+
+	if (err)
+		goto err_free_gpio;
+
+	device_init_wakeup(&pdev->dev, pdata->wakeup);
+	platform_set_drvdata(pdev, keypad);
+
+	return 0;
+
+err_free_gpio:
+	mt_matrix_keypad_free_gpio(keypad);
+
+err_free_mem:
+	input_free_device(input_dev);
+	kfree(keypad);
+	return err;
+}
+
+static int mt_matrix_keypad_remove(struct platform_device *pdev)
+{
+	struct mt_matrix_keypad *keypad = platform_get_drvdata(pdev);
+
+	device_init_wakeup(&pdev->dev, 0);
+	input_unregister_device(keypad->input_dev);
+	mt_matrix_keypad_free_gpio(keypad);
+	kfree(keypad);
+
+	return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id mt_matrix_keypad_dt_match[] = {
+	{ .compatible = "gpio-mt-matrix-keypad" },
+	{}
+};
+MODULE_DEVICE_TABLE(of, mt_matrix_keypad_dt_match);
+#endif
+
+static struct platform_driver mt_matrix_keypad_driver = {
+	.probe		= mt_matrix_keypad_probe,
+	.remove		= mt_matrix_keypad_remove,
+	.driver		= {
+		.name	= "mt-matrix-keypad",
+		.pm	= &mt_matrix_keypad_pm_ops,
+		.of_match_table = of_match_ptr(mt_matrix_keypad_dt_match),
+	},
+};
+module_platform_driver(mt_matrix_keypad_driver);
+
+MODULE_AUTHOR("vinay");
+MODULE_DESCRIPTION("GPIO Driven Mt Matrix Keypad Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:mt-matrix-keypad");
diff --git a/include/linux/input/mt_matrix_keypad.h b/include/linux/input/mt_matrix_keypad.h
new file mode 100644
index 000000000000..46dfe49c5fe1
--- /dev/null
+++ b/include/linux/input/mt_matrix_keypad.h
@@ -0,0 +1,85 @@ 
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _MT_MATRIX_KEYPAD_H
+#define _MT_MATRIX_KEYPAD_H
+
+#include <linux/types.h>
+#include <linux/input.h>
+#include <linux/of.h>
+
+#define MATRIX_MAX_ROWS 32
+#define KEYCODE(keymap) (keymap & 0xFFFF)
+
+struct button_states {
+	uint8_t boPrevious : 1;
+	uint8_t boCurrent : 1;
+	uint8_t boCurrentStateOfHw : 1;
+	uint8_t boCurrentStateOfSw : 1;
+	uint8_t boEnabled : 1;
+	uint8_t boStateAtInit : 1;
+};
+
+union typeEvent {
+	uint8_t ui8Register;
+	struct {
+		uint8_t boGlobalChanged : 1;
+		uint8_t boPressed : 1;
+		uint8_t boReleased : 1;
+	} status;
+};
+
+struct button {
+	uint8_t key;
+	union typeEvent event;
+	struct button_states state;
+};
+
+struct phase {
+	int phase_prepare;
+	int phase_start;
+	int phase_update_button;
+};
+
+struct mt_matrix_keypad_platform_data {
+	const struct mt_keymap_data *keymap_data;
+	const unsigned int *line_gpios;
+	unsigned int num_line_gpios;
+	unsigned int num_of_buttons;
+	unsigned int col_scan_delay_us;
+	unsigned int debounce_ms;
+	unsigned int clustered_irq;
+	unsigned int clustered_irq_flags;
+
+	bool active_low;
+	bool wakeup;
+	bool no_autorepeat;
+	bool intialize_buttons;
+
+	int8_t scan_phase;
+	int8_t *button_matrix;
+	struct button *button_array;
+	struct phase phase_state;
+};
+
+void init_phase(struct mt_matrix_keypad_platform_data *pdata);
+void button_init(struct button *btn, bool btn_hw_state, int key);
+struct button_states get_button_state(struct button *btn);
+union typeEvent get_and_clear_events(struct button *btn);
+uint8_t get_btn_index(struct mt_matrix_keypad_platform_data *pdata,
+		      int btn_key);
+void set_btn_state_by_hw(struct button *btn, bool boButtonState);
+bool check_button_changes(struct button *btn);
+struct button_states
+get_btn_id_state(const struct mt_matrix_keypad_platform_data *pdata,
+		 int btn_index);
+union typeEvent
+get_and_clear_btn_events(const struct mt_matrix_keypad_platform_data *pdata,
+			 int btn_index);
+void button_hdl_init(struct mt_matrix_keypad_platform_data *pdata);
+bool on_button_event(const struct mt_matrix_keypad_platform_data *pdata,
+		     int btn_index, union typeEvent btn_event,
+		     struct input_dev *input_dev);
+void process_button_events(const struct mt_matrix_keypad_platform_data *pdata,
+			   struct input_dev *input_dev);
+void update_buttons(struct mt_matrix_keypad_platform_data *pdata,
+		    struct input_dev *input_dev);
+#endif /* _MT_MATRIX_KEYPAD_H */