Message ID | 20220504105254.1576-2-Gireesh.Hiremath@in.bosch.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | [1/4] ARM: dts: am335x: Guardian: switch to AM33XX_PADCONF pinmux macro | expand |
Hi Gireesh, On 22-05-04, Gireesh.Hiremath@in.bosch.com wrote: > 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 pls can you tell me the main difference between the already existing matrix_keypad.c driver and your driver. If there are only minor differences I would rather add those to the existing driver. Regards, Marco
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
------------------------------------------------------
|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
both matric_keypad.c and mt_matrix_kepad.c logically operate differently,
my openion is not to merge both.
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? > 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". Regards, Marco
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-20220504] [cannot apply to dtor-input/next robh/for-next balbi-usb/testing/next v5.18-rc5] [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/20220504-185623 base: https://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap.git for-next config: sh-allmodconfig (https://download.01.org/0day-ci/archive/20220504/202205042204.lz58BhXF-lkp@intel.com/config) compiler: sh4-linux-gcc (GCC) 11.3.0 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 # https://github.com/intel-lab-lkp/linux/commit/8dae1bf10aa8e74feb1bca5eb708e98e9492a587 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/20220504-185623 git checkout 8dae1bf10aa8e74feb1bca5eb708e98e9492a587 # save the config file mkdir build_dir && cp config build_dir/.config COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.3.0 make.cross W=1 O=build_dir ARCH=sh SHELL=/bin/bash drivers/input/keyboard/ 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:51:6: warning: no previous prototype for 'init_phase' [-Wmissing-prototypes] 51 | void init_phase(struct mt_matrix_keypad_platform_data *pdata) | ^~~~~~~~~~ >> drivers/input/keyboard/mt_matrix_keypad.c:58:6: warning: no previous prototype for 'button_init' [-Wmissing-prototypes] 58 | void button_init(struct button *btn, bool btn_hw_state, int key) | ^~~~~~~~~~~ >> drivers/input/keyboard/mt_matrix_keypad.c:70:1: warning: type qualifiers ignored on function return type [-Wignored-qualifiers] 70 | const struct button_states get_button_state(struct button *btn) | ^~~~~ >> drivers/input/keyboard/mt_matrix_keypad.c:70:28: warning: no previous prototype for 'get_button_state' [-Wmissing-prototypes] 70 | const struct button_states get_button_state(struct button *btn) | ^~~~~~~~~~~~~~~~ >> drivers/input/keyboard/mt_matrix_keypad.c:75:17: warning: no previous prototype for 'get_and_clear_events' [-Wmissing-prototypes] 75 | union typeEvent get_and_clear_events(struct button *btn) | ^~~~~~~~~~~~~~~~~~~~ >> drivers/input/keyboard/mt_matrix_keypad.c:84:9: warning: no previous prototype for 'get_btn_index' [-Wmissing-prototypes] 84 | uint8_t get_btn_index(struct mt_matrix_keypad_platform_data *pdata, int btn_key) | ^~~~~~~~~~~~~ >> drivers/input/keyboard/mt_matrix_keypad.c:95:6: warning: no previous prototype for 'set_btn_state_by_hw' [-Wmissing-prototypes] 95 | void set_btn_state_by_hw(struct button *btn, bool boButtonState) | ^~~~~~~~~~~~~~~~~~~ >> drivers/input/keyboard/mt_matrix_keypad.c:100:6: warning: no previous prototype for 'check_button_changes' [-Wmissing-prototypes] 100 | bool check_button_changes(struct button *btn) | ^~~~~~~~~~~~~~~~~~~~ drivers/input/keyboard/mt_matrix_keypad.c:124:1: warning: type qualifiers ignored on function return type [-Wignored-qualifiers] 124 | const struct button_states | ^~~~~ >> drivers/input/keyboard/mt_matrix_keypad.c:125:1: warning: no previous prototype for 'get_btn_id_state' [-Wmissing-prototypes] 125 | get_btn_id_state(const struct mt_matrix_keypad_platform_data *pdata, | ^~~~~~~~~~~~~~~~ >> drivers/input/keyboard/mt_matrix_keypad.c:135:1: warning: no previous prototype for 'get_and_clear_btn_events' [-Wmissing-prototypes] 135 | get_and_clear_btn_events(const struct mt_matrix_keypad_platform_data *pdata, | ^~~~~~~~~~~~~~~~~~~~~~~~ >> drivers/input/keyboard/mt_matrix_keypad.c:144:6: warning: no previous prototype for 'button_hdl_init' [-Wmissing-prototypes] 144 | void button_hdl_init(struct mt_matrix_keypad_platform_data *pdata) | ^~~~~~~~~~~~~~~ >> drivers/input/keyboard/mt_matrix_keypad.c:171:6: warning: no previous prototype for 'on_button_event' [-Wmissing-prototypes] 171 | bool on_button_event(const struct mt_matrix_keypad_platform_data *pdata, | ^~~~~~~~~~~~~~~ >> drivers/input/keyboard/mt_matrix_keypad.c:196:6: warning: no previous prototype for 'process_button_events' [-Wmissing-prototypes] 196 | void process_button_events(const struct mt_matrix_keypad_platform_data *pdata, | ^~~~~~~~~~~~~~~~~~~~~ >> drivers/input/keyboard/mt_matrix_keypad.c:219:6: warning: no previous prototype for 'update_buttons' [-Wmissing-prototypes] 219 | void update_buttons(struct mt_matrix_keypad_platform_data *pdata, | ^~~~~~~~~~~~~~ vim +/init_phase +51 drivers/input/keyboard/mt_matrix_keypad.c 43 44 static bool 45 get_gpio_line_value(const struct mt_matrix_keypad_platform_data *pdata, 46 int row); 47 static void 48 activate_line_driving(const struct mt_matrix_keypad_platform_data *pdata, 49 int line, bool on); 50 > 51 void init_phase(struct mt_matrix_keypad_platform_data *pdata) 52 { 53 pdata->phase_state.phase_prepare = -1; 54 pdata->phase_state.phase_start = 0; 55 pdata->phase_state.phase_update_button = pdata->num_line_gpios; 56 } 57 > 58 void button_init(struct button *btn, bool btn_hw_state, int key) 59 { 60 btn->state.boPrevious = btn_hw_state; 61 btn->state.boCurrentStateOfHw = btn_hw_state; 62 btn->state.boCurrentStateOfSw = false; 63 btn->state.boCurrent = btn_hw_state; 64 btn->state.boEnabled = true; 65 btn->state.boStateAtInit = btn_hw_state; 66 btn->event.ui8Register = 0; 67 btn->key = key; 68 } 69 > 70 const struct button_states get_button_state(struct button *btn) 71 { 72 return btn->state; 73 } 74 > 75 union typeEvent get_and_clear_events(struct button *btn) 76 { 77 union typeEvent beTemp = btn->event; 78 79 btn->event.ui8Register = 0; 80 81 return beTemp; 82 } 83 > 84 uint8_t get_btn_index(struct mt_matrix_keypad_platform_data *pdata, int btn_key) 85 { 86 uint8_t i; 87 88 for (i = 0; i < pdata->num_of_button; i++) { 89 if (pdata->button_array[i].key == btn_key) 90 break; 91 } 92 return i; 93 } 94 > 95 void set_btn_state_by_hw(struct button *btn, bool boButtonState) 96 { 97 btn->state.boCurrentStateOfHw = boButtonState; 98 } 99 > 100 bool check_button_changes(struct button *btn) 101 { 102 btn->state.boPrevious = btn->state.boCurrent; 103 btn->state.boCurrent = 104 btn->state.boCurrentStateOfHw || btn->state.boCurrentStateOfSw; 105 106 /* Check if Button is pressed */ 107 if ((btn->state.boPrevious == false) && 108 (btn->state.boCurrent == true)) { 109 btn->event.status.boPressed = true; 110 } 111 112 /* Check if Button is released */ 113 else if ((btn->state.boPrevious == true) && 114 (btn->state.boCurrent == false)) { 115 btn->event.status.boReleased = true; 116 } 117 118 if (btn->event.ui8Register != 0) 119 btn->event.status.boGlobalChanged = true; 120 121 return btn->event.status.boGlobalChanged; 122 } 123 > 124 const struct button_states > 125 get_btn_id_state(const struct mt_matrix_keypad_platform_data *pdata, 126 int btn_index) 127 { 128 if (btn_index < pdata->num_of_button) 129 return get_button_state(&pdata->button_array[btn_index]); 130 else 131 return get_button_state(&pdata->button_array[0]); 132 } 133 134 union typeEvent > 135 get_and_clear_btn_events(const struct mt_matrix_keypad_platform_data *pdata, 136 int btn_index) 137 { 138 if (btn_index < pdata->num_of_button) 139 return get_and_clear_events(&pdata->button_array[btn_index]); 140 else 141 return get_and_clear_events(&pdata->button_array[0]); 142 } 143 > 144 void button_hdl_init(struct mt_matrix_keypad_platform_data *pdata) 145 { 146 int row, col, index; 147 int i; 148 149 pdata->scan_phase = pdata->phase_state.phase_prepare; 150 pdata->intialize_buttons = true; 151 152 /* Init Button Objects, will be reinited once states are captured */ 153 i = 0; 154 for (row = 1; row < pdata->num_line_gpios; row++) 155 for (col = 0; col < row; col++) { 156 index = (row * pdata->num_line_gpios) + col; 157 if (pdata->button_matrix[index] != 158 pdata->button_matrix[0]) { 159 if (i < pdata->num_of_button) { 160 button_init( 161 &pdata->button_array[i], false, 162 pdata->button_matrix[index]); 163 i++; 164 } 165 } 166 } 167 168 pr_debug("[%s]: %s Done\n", MODULE_NAME, __func__); 169 } 170 > 171 bool on_button_event(const struct mt_matrix_keypad_platform_data *pdata, 172 int btn_index, union typeEvent btn_event, 173 struct input_dev *input_dev) 174 { 175 bool any_btn_served = true; 176 unsigned int key_code = 0; 177 int key_value = 0; 178 179 key_code = pdata->button_array[btn_index].key; 180 181 if (btn_event.status.boPressed) { 182 key_value = 1; 183 pr_debug("[%s]:%d Pressed\n", MODULE_NAME, key_code); 184 } 185 186 if (btn_event.status.boReleased) { 187 key_value = 0; 188 pr_debug("[%s]:%d Released\n", MODULE_NAME, key_code); 189 } 190 191 input_report_key(input_dev, key_code, key_value); 192 input_sync(input_dev); 193 return any_btn_served; 194 } 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_button; 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_button; 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_button; 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
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-20220504] [cannot apply to dtor-input/next robh/for-next v5.18-rc5] [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/20220504-185623 base: https://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap.git for-next config: x86_64-allmodconfig (https://download.01.org/0day-ci/archive/20220505/202205050513.PAcNKUP3-lkp@intel.com/config) compiler: clang version 15.0.0 (https://github.com/llvm/llvm-project 363b3a645a1e30011cc8da624f13dac5fd915628) 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 # https://github.com/intel-lab-lkp/linux/commit/8dae1bf10aa8e74feb1bca5eb708e98e9492a587 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/20220504-185623 git checkout 8dae1bf10aa8e74feb1bca5eb708e98e9492a587 # save the config file mkdir build_dir && cp config build_dir/.config COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=x86_64 SHELL=/bin/bash drivers/input/keyboard/ 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:51:6: warning: no previous prototype for function 'init_phase' [-Wmissing-prototypes] void init_phase(struct mt_matrix_keypad_platform_data *pdata) ^ drivers/input/keyboard/mt_matrix_keypad.c:51:1: note: declare 'static' if the function is not intended to be used outside of this translation unit void init_phase(struct mt_matrix_keypad_platform_data *pdata) ^ static >> drivers/input/keyboard/mt_matrix_keypad.c:58:6: warning: no previous prototype for function 'button_init' [-Wmissing-prototypes] void button_init(struct button *btn, bool btn_hw_state, int key) ^ drivers/input/keyboard/mt_matrix_keypad.c:58:1: note: declare 'static' if the function is not intended to be used outside of this translation unit void button_init(struct button *btn, bool btn_hw_state, int key) ^ static >> drivers/input/keyboard/mt_matrix_keypad.c:70:1: warning: 'const' type qualifier on return type has no effect [-Wignored-qualifiers] const struct button_states get_button_state(struct button *btn) ^~~~~~ >> drivers/input/keyboard/mt_matrix_keypad.c:70:28: warning: no previous prototype for function 'get_button_state' [-Wmissing-prototypes] const struct button_states get_button_state(struct button *btn) ^ drivers/input/keyboard/mt_matrix_keypad.c:70:7: note: declare 'static' if the function is not intended to be used outside of this translation unit const struct button_states get_button_state(struct button *btn) ^ static >> drivers/input/keyboard/mt_matrix_keypad.c:75:17: warning: no previous prototype for function 'get_and_clear_events' [-Wmissing-prototypes] union typeEvent get_and_clear_events(struct button *btn) ^ drivers/input/keyboard/mt_matrix_keypad.c:75:1: note: declare 'static' if the function is not intended to be used outside of this translation unit union typeEvent get_and_clear_events(struct button *btn) ^ static >> drivers/input/keyboard/mt_matrix_keypad.c:84:9: warning: no previous prototype for function 'get_btn_index' [-Wmissing-prototypes] uint8_t get_btn_index(struct mt_matrix_keypad_platform_data *pdata, int btn_key) ^ drivers/input/keyboard/mt_matrix_keypad.c:84:1: note: declare 'static' if the function is not intended to be used outside of this translation unit uint8_t get_btn_index(struct mt_matrix_keypad_platform_data *pdata, int btn_key) ^ static >> drivers/input/keyboard/mt_matrix_keypad.c:95:6: warning: no previous prototype for function 'set_btn_state_by_hw' [-Wmissing-prototypes] void set_btn_state_by_hw(struct button *btn, bool boButtonState) ^ drivers/input/keyboard/mt_matrix_keypad.c:95:1: note: declare 'static' if the function is not intended to be used outside of this translation unit void set_btn_state_by_hw(struct button *btn, bool boButtonState) ^ static >> drivers/input/keyboard/mt_matrix_keypad.c:100:6: warning: no previous prototype for function 'check_button_changes' [-Wmissing-prototypes] bool check_button_changes(struct button *btn) ^ drivers/input/keyboard/mt_matrix_keypad.c:100:1: note: declare 'static' if the function is not intended to be used outside of this translation unit bool check_button_changes(struct button *btn) ^ static drivers/input/keyboard/mt_matrix_keypad.c:124:1: warning: 'const' type qualifier on return type has no effect [-Wignored-qualifiers] const struct button_states ^~~~~~ >> drivers/input/keyboard/mt_matrix_keypad.c:125:1: warning: no previous prototype for function 'get_btn_id_state' [-Wmissing-prototypes] get_btn_id_state(const struct mt_matrix_keypad_platform_data *pdata, ^ drivers/input/keyboard/mt_matrix_keypad.c:124:7: note: declare 'static' if the function is not intended to be used outside of this translation unit const struct button_states ^ static >> drivers/input/keyboard/mt_matrix_keypad.c:135:1: warning: no previous prototype for function 'get_and_clear_btn_events' [-Wmissing-prototypes] get_and_clear_btn_events(const struct mt_matrix_keypad_platform_data *pdata, ^ drivers/input/keyboard/mt_matrix_keypad.c:134:1: note: declare 'static' if the function is not intended to be used outside of this translation unit union typeEvent ^ static >> drivers/input/keyboard/mt_matrix_keypad.c:144:6: warning: no previous prototype for function 'button_hdl_init' [-Wmissing-prototypes] void button_hdl_init(struct mt_matrix_keypad_platform_data *pdata) ^ drivers/input/keyboard/mt_matrix_keypad.c:144:1: note: declare 'static' if the function is not intended to be used outside of this translation unit void button_hdl_init(struct mt_matrix_keypad_platform_data *pdata) ^ static >> drivers/input/keyboard/mt_matrix_keypad.c:171:6: warning: no previous prototype for function 'on_button_event' [-Wmissing-prototypes] bool on_button_event(const struct mt_matrix_keypad_platform_data *pdata, ^ drivers/input/keyboard/mt_matrix_keypad.c:171:1: note: declare 'static' if the function is not intended to be used outside of this translation unit bool on_button_event(const struct mt_matrix_keypad_platform_data *pdata, ^ static >> 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; ^ >> drivers/input/keyboard/mt_matrix_keypad.c:196:6: warning: no previous prototype for function 'process_button_events' [-Wmissing-prototypes] void process_button_events(const struct mt_matrix_keypad_platform_data *pdata, ^ drivers/input/keyboard/mt_matrix_keypad.c:196:1: note: declare 'static' if the function is not intended to be used outside of this translation unit void process_button_events(const struct mt_matrix_keypad_platform_data *pdata, ^ static >> drivers/input/keyboard/mt_matrix_keypad.c:219:6: warning: no previous prototype for function 'update_buttons' [-Wmissing-prototypes] void update_buttons(struct mt_matrix_keypad_platform_data *pdata, ^ drivers/input/keyboard/mt_matrix_keypad.c:219:1: note: declare 'static' if the function is not intended to be used outside of this translation unit void update_buttons(struct mt_matrix_keypad_platform_data *pdata, ^ static 16 warnings generated. vim +/init_phase +51 drivers/input/keyboard/mt_matrix_keypad.c 43 44 static bool 45 get_gpio_line_value(const struct mt_matrix_keypad_platform_data *pdata, 46 int row); 47 static void 48 activate_line_driving(const struct mt_matrix_keypad_platform_data *pdata, 49 int line, bool on); 50 > 51 void init_phase(struct mt_matrix_keypad_platform_data *pdata) 52 { 53 pdata->phase_state.phase_prepare = -1; 54 pdata->phase_state.phase_start = 0; 55 pdata->phase_state.phase_update_button = pdata->num_line_gpios; 56 } 57 > 58 void button_init(struct button *btn, bool btn_hw_state, int key) 59 { 60 btn->state.boPrevious = btn_hw_state; 61 btn->state.boCurrentStateOfHw = btn_hw_state; 62 btn->state.boCurrentStateOfSw = false; 63 btn->state.boCurrent = btn_hw_state; 64 btn->state.boEnabled = true; 65 btn->state.boStateAtInit = btn_hw_state; 66 btn->event.ui8Register = 0; 67 btn->key = key; 68 } 69 > 70 const struct button_states get_button_state(struct button *btn) 71 { 72 return btn->state; 73 } 74 > 75 union typeEvent get_and_clear_events(struct button *btn) 76 { 77 union typeEvent beTemp = btn->event; 78 79 btn->event.ui8Register = 0; 80 81 return beTemp; 82 } 83 > 84 uint8_t get_btn_index(struct mt_matrix_keypad_platform_data *pdata, int btn_key) 85 { 86 uint8_t i; 87 88 for (i = 0; i < pdata->num_of_button; i++) { 89 if (pdata->button_array[i].key == btn_key) 90 break; 91 } 92 return i; 93 } 94 > 95 void set_btn_state_by_hw(struct button *btn, bool boButtonState) 96 { 97 btn->state.boCurrentStateOfHw = boButtonState; 98 } 99 > 100 bool check_button_changes(struct button *btn) 101 { 102 btn->state.boPrevious = btn->state.boCurrent; 103 btn->state.boCurrent = 104 btn->state.boCurrentStateOfHw || btn->state.boCurrentStateOfSw; 105 106 /* Check if Button is pressed */ 107 if ((btn->state.boPrevious == false) && 108 (btn->state.boCurrent == true)) { 109 btn->event.status.boPressed = true; 110 } 111 112 /* Check if Button is released */ 113 else if ((btn->state.boPrevious == true) && 114 (btn->state.boCurrent == false)) { 115 btn->event.status.boReleased = true; 116 } 117 118 if (btn->event.ui8Register != 0) 119 btn->event.status.boGlobalChanged = true; 120 121 return btn->event.status.boGlobalChanged; 122 } 123 124 const struct button_states > 125 get_btn_id_state(const struct mt_matrix_keypad_platform_data *pdata, 126 int btn_index) 127 { 128 if (btn_index < pdata->num_of_button) 129 return get_button_state(&pdata->button_array[btn_index]); 130 else 131 return get_button_state(&pdata->button_array[0]); 132 } 133 134 union typeEvent > 135 get_and_clear_btn_events(const struct mt_matrix_keypad_platform_data *pdata, 136 int btn_index) 137 { 138 if (btn_index < pdata->num_of_button) 139 return get_and_clear_events(&pdata->button_array[btn_index]); 140 else 141 return get_and_clear_events(&pdata->button_array[0]); 142 } 143 > 144 void button_hdl_init(struct mt_matrix_keypad_platform_data *pdata) 145 { 146 int row, col, index; 147 int i; 148 149 pdata->scan_phase = pdata->phase_state.phase_prepare; 150 pdata->intialize_buttons = true; 151 152 /* Init Button Objects, will be reinited once states are captured */ 153 i = 0; 154 for (row = 1; row < pdata->num_line_gpios; row++) 155 for (col = 0; col < row; col++) { 156 index = (row * pdata->num_line_gpios) + col; 157 if (pdata->button_matrix[index] != 158 pdata->button_matrix[0]) { 159 if (i < pdata->num_of_button) { 160 button_init( 161 &pdata->button_array[i], false, 162 pdata->button_matrix[index]); 163 i++; 164 } 165 } 166 } 167 168 pr_debug("[%s]: %s Done\n", MODULE_NAME, __func__); 169 } 170 > 171 bool on_button_event(const struct mt_matrix_keypad_platform_data *pdata, 172 int btn_index, union typeEvent btn_event, 173 struct input_dev *input_dev) 174 { 175 bool any_btn_served = true; 176 unsigned int key_code = 0; 177 int key_value = 0; 178 179 key_code = pdata->button_array[btn_index].key; 180 181 if (btn_event.status.boPressed) { 182 key_value = 1; 183 pr_debug("[%s]:%d Pressed\n", MODULE_NAME, key_code); 184 } 185 186 if (btn_event.status.boReleased) { 187 key_value = 0; 188 pr_debug("[%s]:%d Released\n", MODULE_NAME, key_code); 189 } 190 191 input_report_key(input_dev, key_code, key_value); 192 input_sync(input_dev); 193 return any_btn_served; 194 } 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_button; 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_button; 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_button; 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
On 04/05/2022 16:14, Marco Felsch wrote: > 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? 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. Best regards, Krzysztof
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..9310faf8b237 --- /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; +} + +const 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_button; 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; +} + +const struct button_states +get_btn_id_state(const struct mt_matrix_keypad_platform_data *pdata, + int btn_index) +{ + if (btn_index < pdata->num_of_button) + 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_button) + 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_button) { + 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_button; 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_button; 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_button; + 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-button", &pdata->num_of_button); + if (pdata->num_of_button <= 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_button), + 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..8c5fbf109dbc --- /dev/null +++ b/include/linux/input/mt_matrix_keypad.h @@ -0,0 +1,63 @@ +/* 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_button; + 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; +}; + +#endif /* _MT_MATRIX_KEYPAD_H */