Message ID | 20220506072737.1590-2-Gireesh.Hiremath@in.bosch.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | [v2,1/4] ARM: dts: am335x: Guardian: switch to AM33XX_PADCONF pinmux macro | expand |
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
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
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
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
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
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
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
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 --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 */