diff options
| -rw-r--r-- | drivers/input/keyboard/Kconfig | 10 | ||||
| -rw-r--r-- | drivers/input/keyboard/Makefile | 1 | ||||
| -rw-r--r-- | drivers/input/keyboard/tc3589x-keypad.c | 472 | ||||
| -rw-r--r-- | drivers/mfd/tc3589x.c | 28 | ||||
| -rw-r--r-- | include/linux/mfd/tc3589x.h | 52 |
5 files changed, 562 insertions, 1 deletions
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index b8c51b9781db..85af3c3f7bcb 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig | |||
| @@ -443,6 +443,16 @@ config KEYBOARD_OMAP4 | |||
| 443 | To compile this driver as a module, choose M here: the | 443 | To compile this driver as a module, choose M here: the |
| 444 | module will be called omap4-keypad. | 444 | module will be called omap4-keypad. |
| 445 | 445 | ||
| 446 | config KEYBOARD_TC3589X | ||
| 447 | tristate "TC3589X Keypad support" | ||
| 448 | depends on MFD_TC3589X | ||
| 449 | help | ||
| 450 | Say Y here if you want to use the keypad controller on | ||
| 451 | TC35892/3 I/O expander. | ||
| 452 | |||
| 453 | To compile this driver as a module, choose M here: the | ||
| 454 | module will be called tc3589x-keypad. | ||
| 455 | |||
| 446 | config KEYBOARD_TNETV107X | 456 | config KEYBOARD_TNETV107X |
| 447 | tristate "TI TNETV107X keypad support" | 457 | tristate "TI TNETV107X keypad support" |
| 448 | depends on ARCH_DAVINCI_TNETV107X | 458 | depends on ARCH_DAVINCI_TNETV107X |
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index a34452e8ebe2..4411c70db3b5 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile | |||
| @@ -40,6 +40,7 @@ obj-$(CONFIG_KEYBOARD_SH_KEYSC) += sh_keysc.o | |||
| 40 | obj-$(CONFIG_KEYBOARD_STMPE) += stmpe-keypad.o | 40 | obj-$(CONFIG_KEYBOARD_STMPE) += stmpe-keypad.o |
| 41 | obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o | 41 | obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o |
| 42 | obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o | 42 | obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o |
| 43 | obj-$(CONFIG_KEYBOARD_TC3589X) += tc3589x-keypad.o | ||
| 43 | obj-$(CONFIG_KEYBOARD_TNETV107X) += tnetv107x-keypad.o | 44 | obj-$(CONFIG_KEYBOARD_TNETV107X) += tnetv107x-keypad.o |
| 44 | obj-$(CONFIG_KEYBOARD_TWL4030) += twl4030_keypad.o | 45 | obj-$(CONFIG_KEYBOARD_TWL4030) += twl4030_keypad.o |
| 45 | obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o | 46 | obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o |
diff --git a/drivers/input/keyboard/tc3589x-keypad.c b/drivers/input/keyboard/tc3589x-keypad.c new file mode 100644 index 000000000000..69dc0cb20a00 --- /dev/null +++ b/drivers/input/keyboard/tc3589x-keypad.c | |||
| @@ -0,0 +1,472 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) ST-Ericsson SA 2010 | ||
| 3 | * | ||
| 4 | * Author: Jayeeta Banerjee <jayeeta.banerjee@stericsson.com> | ||
| 5 | * Author: Sundar Iyer <sundar.iyer@stericsson.com> | ||
| 6 | * | ||
| 7 | * License Terms: GNU General Public License, version 2 | ||
| 8 | * | ||
| 9 | * TC35893 MFD Keypad Controller driver | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <linux/module.h> | ||
| 13 | #include <linux/init.h> | ||
| 14 | #include <linux/interrupt.h> | ||
| 15 | #include <linux/input.h> | ||
| 16 | #include <linux/platform_device.h> | ||
| 17 | #include <linux/input/matrix_keypad.h> | ||
| 18 | #include <linux/i2c.h> | ||
| 19 | #include <linux/slab.h> | ||
| 20 | #include <linux/mfd/tc3589x.h> | ||
| 21 | |||
| 22 | /* Maximum supported keypad matrix row/columns size */ | ||
| 23 | #define TC3589x_MAX_KPROW 8 | ||
| 24 | #define TC3589x_MAX_KPCOL 12 | ||
| 25 | |||
| 26 | /* keypad related Constants */ | ||
| 27 | #define TC3589x_MAX_DEBOUNCE_SETTLE 0xFF | ||
| 28 | #define DEDICATED_KEY_VAL 0xFF | ||
| 29 | |||
| 30 | /* Pull up/down masks */ | ||
| 31 | #define TC3589x_NO_PULL_MASK 0x0 | ||
| 32 | #define TC3589x_PULL_DOWN_MASK 0x1 | ||
| 33 | #define TC3589x_PULL_UP_MASK 0x2 | ||
| 34 | #define TC3589x_PULLUP_ALL_MASK 0xAA | ||
| 35 | #define TC3589x_IO_PULL_VAL(index, mask) ((mask)<<((index)%4)*2)) | ||
| 36 | |||
| 37 | /* Bit masks for IOCFG register */ | ||
| 38 | #define IOCFG_BALLCFG 0x01 | ||
| 39 | #define IOCFG_IG 0x08 | ||
| 40 | |||
| 41 | #define KP_EVCODE_COL_MASK 0x0F | ||
| 42 | #define KP_EVCODE_ROW_MASK 0x70 | ||
| 43 | #define KP_RELEASE_EVT_MASK 0x80 | ||
| 44 | |||
| 45 | #define KP_ROW_SHIFT 4 | ||
| 46 | |||
| 47 | #define KP_NO_VALID_KEY_MASK 0x7F | ||
| 48 | |||
| 49 | /* bit masks for RESTCTRL register */ | ||
| 50 | #define TC3589x_KBDRST 0x2 | ||
| 51 | #define TC3589x_IRQRST 0x10 | ||
| 52 | #define TC3589x_RESET_ALL 0x1B | ||
| 53 | |||
| 54 | /* KBDMFS register bit mask */ | ||
| 55 | #define TC3589x_KBDMFS_EN 0x1 | ||
| 56 | |||
| 57 | /* CLKEN register bitmask */ | ||
| 58 | #define KPD_CLK_EN 0x1 | ||
| 59 | |||
| 60 | /* RSTINTCLR register bit mask */ | ||
| 61 | #define IRQ_CLEAR 0x1 | ||
| 62 | |||
| 63 | /* bit masks for keyboard interrupts*/ | ||
| 64 | #define TC3589x_EVT_LOSS_INT 0x8 | ||
| 65 | #define TC3589x_EVT_INT 0x4 | ||
| 66 | #define TC3589x_KBD_LOSS_INT 0x2 | ||
| 67 | #define TC3589x_KBD_INT 0x1 | ||
| 68 | |||
| 69 | /* bit masks for keyboard interrupt clear*/ | ||
| 70 | #define TC3589x_EVT_INT_CLR 0x2 | ||
| 71 | #define TC3589x_KBD_INT_CLR 0x1 | ||
| 72 | |||
| 73 | #define TC3589x_KBD_KEYMAP_SIZE 64 | ||
| 74 | |||
| 75 | /** | ||
| 76 | * struct tc_keypad - data structure used by keypad driver | ||
| 77 | * @input: pointer to input device object | ||
| 78 | * @board: keypad platform device | ||
| 79 | * @krow: number of rows | ||
| 80 | * @kcol: number of coloumns | ||
| 81 | * @keymap: matrix scan code table for keycodes | ||
| 82 | */ | ||
| 83 | struct tc_keypad { | ||
| 84 | struct tc3589x *tc3589x; | ||
| 85 | struct input_dev *input; | ||
| 86 | const struct tc3589x_keypad_platform_data *board; | ||
| 87 | unsigned int krow; | ||
| 88 | unsigned int kcol; | ||
| 89 | unsigned short keymap[TC3589x_KBD_KEYMAP_SIZE]; | ||
| 90 | bool keypad_stopped; | ||
| 91 | }; | ||
| 92 | |||
| 93 | static int __devinit tc3589x_keypad_init_key_hardware(struct tc_keypad *keypad) | ||
| 94 | { | ||
| 95 | int ret; | ||
| 96 | struct tc3589x *tc3589x = keypad->tc3589x; | ||
| 97 | u8 settle_time = keypad->board->settle_time; | ||
| 98 | u8 dbounce_period = keypad->board->debounce_period; | ||
| 99 | u8 rows = keypad->board->krow & 0xf; /* mask out the nibble */ | ||
| 100 | u8 column = keypad->board->kcol & 0xf; /* mask out the nibble */ | ||
| 101 | |||
| 102 | /* validate platform configurations */ | ||
| 103 | if (keypad->board->kcol > TC3589x_MAX_KPCOL || | ||
| 104 | keypad->board->krow > TC3589x_MAX_KPROW || | ||
| 105 | keypad->board->debounce_period > TC3589x_MAX_DEBOUNCE_SETTLE || | ||
| 106 | keypad->board->settle_time > TC3589x_MAX_DEBOUNCE_SETTLE) | ||
| 107 | return -EINVAL; | ||
| 108 | |||
| 109 | /* configure KBDSIZE 4 LSbits for cols and 4 MSbits for rows */ | ||
| 110 | ret = tc3589x_reg_write(tc3589x, TC3589x_KBDSIZE, | ||
| 111 | (rows << KP_ROW_SHIFT) | column); | ||
| 112 | if (ret < 0) | ||
| 113 | return ret; | ||
| 114 | |||
| 115 | /* configure dedicated key config, no dedicated key selected */ | ||
| 116 | ret = tc3589x_reg_write(tc3589x, TC3589x_KBCFG_LSB, DEDICATED_KEY_VAL); | ||
| 117 | if (ret < 0) | ||
| 118 | return ret; | ||
| 119 | |||
| 120 | ret = tc3589x_reg_write(tc3589x, TC3589x_KBCFG_MSB, DEDICATED_KEY_VAL); | ||
| 121 | if (ret < 0) | ||
| 122 | return ret; | ||
| 123 | |||
| 124 | /* Configure settle time */ | ||
| 125 | ret = tc3589x_reg_write(tc3589x, TC3589x_KBDSETTLE_REG, settle_time); | ||
| 126 | if (ret < 0) | ||
| 127 | return ret; | ||
| 128 | |||
| 129 | /* Configure debounce time */ | ||
| 130 | ret = tc3589x_reg_write(tc3589x, TC3589x_KBDBOUNCE, dbounce_period); | ||
| 131 | if (ret < 0) | ||
| 132 | return ret; | ||
| 133 | |||
| 134 | /* Start of initialise keypad GPIOs */ | ||
| 135 | ret = tc3589x_set_bits(tc3589x, TC3589x_IOCFG, 0x0, IOCFG_IG); | ||
| 136 | if (ret < 0) | ||
| 137 | return ret; | ||
| 138 | |||
| 139 | /* Configure pull-up resistors for all row GPIOs */ | ||
| 140 | ret = tc3589x_reg_write(tc3589x, TC3589x_IOPULLCFG0_LSB, | ||
| 141 | TC3589x_PULLUP_ALL_MASK); | ||
| 142 | if (ret < 0) | ||
| 143 | return ret; | ||
| 144 | |||
| 145 | ret = tc3589x_reg_write(tc3589x, TC3589x_IOPULLCFG0_MSB, | ||
| 146 | TC3589x_PULLUP_ALL_MASK); | ||
| 147 | if (ret < 0) | ||
| 148 | return ret; | ||
| 149 | |||
| 150 | /* Configure pull-up resistors for all column GPIOs */ | ||
| 151 | ret = tc3589x_reg_write(tc3589x, TC3589x_IOPULLCFG1_LSB, | ||
| 152 | TC3589x_PULLUP_ALL_MASK); | ||
| 153 | if (ret < 0) | ||
| 154 | return ret; | ||
| 155 | |||
| 156 | ret = tc3589x_reg_write(tc3589x, TC3589x_IOPULLCFG1_MSB, | ||
| 157 | TC3589x_PULLUP_ALL_MASK); | ||
| 158 | if (ret < 0) | ||
| 159 | return ret; | ||
| 160 | |||
| 161 | ret = tc3589x_reg_write(tc3589x, TC3589x_IOPULLCFG2_LSB, | ||
| 162 | TC3589x_PULLUP_ALL_MASK); | ||
| 163 | |||
| 164 | return ret; | ||
| 165 | } | ||
| 166 | |||
| 167 | #define TC35893_DATA_REGS 4 | ||
| 168 | #define TC35893_KEYCODE_FIFO_EMPTY 0x7f | ||
| 169 | #define TC35893_KEYCODE_FIFO_CLEAR 0xff | ||
| 170 | #define TC35893_KEYPAD_ROW_SHIFT 0x3 | ||
| 171 | |||
| 172 | static irqreturn_t tc3589x_keypad_irq(int irq, void *dev) | ||
| 173 | { | ||
| 174 | struct tc_keypad *keypad = dev; | ||
| 175 | struct tc3589x *tc3589x = keypad->tc3589x; | ||
| 176 | u8 i, row_index, col_index, kbd_code, up; | ||
| 177 | u8 code; | ||
| 178 | |||
| 179 | for (i = 0; i < TC35893_DATA_REGS * 2; i++) { | ||
| 180 | kbd_code = tc3589x_reg_read(tc3589x, TC3589x_EVTCODE_FIFO); | ||
| 181 | |||
| 182 | /* loop till fifo is empty and no more keys are pressed */ | ||
| 183 | if (kbd_code == TC35893_KEYCODE_FIFO_EMPTY || | ||
| 184 | kbd_code == TC35893_KEYCODE_FIFO_CLEAR) | ||
| 185 | continue; | ||
| 186 | |||
| 187 | /* valid key is found */ | ||
| 188 | col_index = kbd_code & KP_EVCODE_COL_MASK; | ||
| 189 | row_index = (kbd_code & KP_EVCODE_ROW_MASK) >> KP_ROW_SHIFT; | ||
| 190 | code = MATRIX_SCAN_CODE(row_index, col_index, | ||
| 191 | TC35893_KEYPAD_ROW_SHIFT); | ||
| 192 | up = kbd_code & KP_RELEASE_EVT_MASK; | ||
| 193 | |||
| 194 | input_event(keypad->input, EV_MSC, MSC_SCAN, code); | ||
| 195 | input_report_key(keypad->input, keypad->keymap[code], !up); | ||
| 196 | input_sync(keypad->input); | ||
| 197 | } | ||
| 198 | |||
| 199 | /* clear IRQ */ | ||
| 200 | tc3589x_set_bits(tc3589x, TC3589x_KBDIC, | ||
| 201 | 0x0, TC3589x_EVT_INT_CLR | TC3589x_KBD_INT_CLR); | ||
| 202 | /* enable IRQ */ | ||
| 203 | tc3589x_set_bits(tc3589x, TC3589x_KBDMSK, | ||
| 204 | 0x0, TC3589x_EVT_LOSS_INT | TC3589x_EVT_INT); | ||
| 205 | |||
| 206 | return IRQ_HANDLED; | ||
| 207 | } | ||
| 208 | |||
| 209 | static int tc3589x_keypad_enable(struct tc_keypad *keypad) | ||
| 210 | { | ||
| 211 | struct tc3589x *tc3589x = keypad->tc3589x; | ||
| 212 | int ret; | ||
| 213 | |||
| 214 | /* pull the keypad module out of reset */ | ||
| 215 | ret = tc3589x_set_bits(tc3589x, TC3589x_RSTCTRL, TC3589x_KBDRST, 0x0); | ||
| 216 | if (ret < 0) | ||
| 217 | return ret; | ||
| 218 | |||
| 219 | /* configure KBDMFS */ | ||
| 220 | ret = tc3589x_set_bits(tc3589x, TC3589x_KBDMFS, 0x0, TC3589x_KBDMFS_EN); | ||
| 221 | if (ret < 0) | ||
| 222 | return ret; | ||
| 223 | |||
| 224 | /* enable the keypad clock */ | ||
| 225 | ret = tc3589x_set_bits(tc3589x, TC3589x_CLKEN, 0x0, KPD_CLK_EN); | ||
| 226 | if (ret < 0) | ||
| 227 | return ret; | ||
| 228 | |||
| 229 | /* clear pending IRQs */ | ||
| 230 | ret = tc3589x_set_bits(tc3589x, TC3589x_RSTINTCLR, 0x0, 0x1); | ||
| 231 | if (ret < 0) | ||
| 232 | return ret; | ||
| 233 | |||
| 234 | /* enable the IRQs */ | ||
| 235 | ret = tc3589x_set_bits(tc3589x, TC3589x_KBDMSK, 0x0, | ||
| 236 | TC3589x_EVT_LOSS_INT | TC3589x_EVT_INT); | ||
| 237 | if (ret < 0) | ||
| 238 | return ret; | ||
| 239 | |||
| 240 | keypad->keypad_stopped = false; | ||
| 241 | |||
| 242 | return ret; | ||
| 243 | } | ||
| 244 | |||
| 245 | static int tc3589x_keypad_disable(struct tc_keypad *keypad) | ||
| 246 | { | ||
| 247 | struct tc3589x *tc3589x = keypad->tc3589x; | ||
| 248 | int ret; | ||
| 249 | |||
| 250 | /* clear IRQ */ | ||
| 251 | ret = tc3589x_set_bits(tc3589x, TC3589x_KBDIC, | ||
| 252 | 0x0, TC3589x_EVT_INT_CLR | TC3589x_KBD_INT_CLR); | ||
| 253 | if (ret < 0) | ||
| 254 | return ret; | ||
| 255 | |||
| 256 | /* disable all interrupts */ | ||
| 257 | ret = tc3589x_set_bits(tc3589x, TC3589x_KBDMSK, | ||
| 258 | ~(TC3589x_EVT_LOSS_INT | TC3589x_EVT_INT), 0x0); | ||
| 259 | if (ret < 0) | ||
| 260 | return ret; | ||
| 261 | |||
| 262 | /* disable the keypad module */ | ||
| 263 | ret = tc3589x_set_bits(tc3589x, TC3589x_CLKEN, 0x1, 0x0); | ||
| 264 | if (ret < 0) | ||
| 265 | return ret; | ||
| 266 | |||
| 267 | /* put the keypad module into reset */ | ||
| 268 | ret = tc3589x_set_bits(tc3589x, TC3589x_RSTCTRL, TC3589x_KBDRST, 0x1); | ||
| 269 | |||
| 270 | keypad->keypad_stopped = true; | ||
| 271 | |||
| 272 | return ret; | ||
| 273 | } | ||
| 274 | |||
| 275 | static int tc3589x_keypad_open(struct input_dev *input) | ||
| 276 | { | ||
| 277 | int error; | ||
| 278 | struct tc_keypad *keypad = input_get_drvdata(input); | ||
| 279 | |||
| 280 | /* enable the keypad module */ | ||
| 281 | error = tc3589x_keypad_enable(keypad); | ||
| 282 | if (error < 0) { | ||
| 283 | dev_err(&input->dev, "failed to enable keypad module\n"); | ||
| 284 | return error; | ||
| 285 | } | ||
| 286 | |||
| 287 | error = tc3589x_keypad_init_key_hardware(keypad); | ||
| 288 | if (error < 0) { | ||
| 289 | dev_err(&input->dev, "failed to configure keypad module\n"); | ||
| 290 | return error; | ||
| 291 | } | ||
| 292 | |||
| 293 | return 0; | ||
| 294 | } | ||
| 295 | |||
| 296 | static void tc3589x_keypad_close(struct input_dev *input) | ||
| 297 | { | ||
| 298 | struct tc_keypad *keypad = input_get_drvdata(input); | ||
| 299 | |||
| 300 | /* disable the keypad module */ | ||
| 301 | tc3589x_keypad_disable(keypad); | ||
| 302 | } | ||
| 303 | |||
| 304 | static int __devinit tc3589x_keypad_probe(struct platform_device *pdev) | ||
| 305 | { | ||
| 306 | struct tc3589x *tc3589x = dev_get_drvdata(pdev->dev.parent); | ||
| 307 | struct tc_keypad *keypad; | ||
| 308 | struct input_dev *input; | ||
| 309 | const struct tc3589x_keypad_platform_data *plat; | ||
| 310 | int error, irq; | ||
| 311 | |||
| 312 | plat = tc3589x->pdata->keypad; | ||
| 313 | if (!plat) { | ||
| 314 | dev_err(&pdev->dev, "invalid keypad platform data\n"); | ||
| 315 | return -EINVAL; | ||
| 316 | } | ||
| 317 | |||
| 318 | irq = platform_get_irq(pdev, 0); | ||
| 319 | if (irq < 0) | ||
| 320 | return irq; | ||
| 321 | |||
| 322 | keypad = kzalloc(sizeof(struct tc_keypad), GFP_KERNEL); | ||
| 323 | input = input_allocate_device(); | ||
| 324 | if (!keypad || !input) { | ||
| 325 | dev_err(&pdev->dev, "failed to allocate keypad memory\n"); | ||
| 326 | error = -ENOMEM; | ||
| 327 | goto err_free_mem; | ||
| 328 | } | ||
| 329 | |||
| 330 | keypad->board = plat; | ||
| 331 | keypad->input = input; | ||
| 332 | keypad->tc3589x = tc3589x; | ||
| 333 | |||
| 334 | input->id.bustype = BUS_I2C; | ||
| 335 | input->name = pdev->name; | ||
| 336 | input->dev.parent = &pdev->dev; | ||
| 337 | |||
| 338 | input->keycode = keypad->keymap; | ||
| 339 | input->keycodesize = sizeof(keypad->keymap[0]); | ||
| 340 | input->keycodemax = ARRAY_SIZE(keypad->keymap); | ||
| 341 | |||
| 342 | input->open = tc3589x_keypad_open; | ||
| 343 | input->close = tc3589x_keypad_close; | ||
| 344 | |||
| 345 | input_set_drvdata(input, keypad); | ||
| 346 | |||
| 347 | input_set_capability(input, EV_MSC, MSC_SCAN); | ||
| 348 | |||
| 349 | __set_bit(EV_KEY, input->evbit); | ||
| 350 | if (!plat->no_autorepeat) | ||
| 351 | __set_bit(EV_REP, input->evbit); | ||
| 352 | |||
| 353 | matrix_keypad_build_keymap(plat->keymap_data, 0x3, | ||
| 354 | input->keycode, input->keybit); | ||
| 355 | |||
| 356 | error = request_threaded_irq(irq, NULL, | ||
| 357 | tc3589x_keypad_irq, plat->irqtype, | ||
| 358 | "tc3589x-keypad", keypad); | ||
| 359 | if (error < 0) { | ||
| 360 | dev_err(&pdev->dev, | ||
| 361 | "Could not allocate irq %d,error %d\n", | ||
| 362 | irq, error); | ||
| 363 | goto err_free_mem; | ||
| 364 | } | ||
| 365 | |||
| 366 | error = input_register_device(input); | ||
| 367 | if (error) { | ||
| 368 | dev_err(&pdev->dev, "Could not register input device\n"); | ||
| 369 | goto err_free_irq; | ||
| 370 | } | ||
| 371 | |||
| 372 | /* let platform decide if keypad is a wakeup source or not */ | ||
| 373 | device_init_wakeup(&pdev->dev, plat->enable_wakeup); | ||
| 374 | device_set_wakeup_capable(&pdev->dev, plat->enable_wakeup); | ||
| 375 | |||
| 376 | platform_set_drvdata(pdev, keypad); | ||
| 377 | |||
| 378 | return 0; | ||
| 379 | |||
| 380 | err_free_irq: | ||
| 381 | free_irq(irq, keypad); | ||
| 382 | err_free_mem: | ||
| 383 | input_free_device(input); | ||
| 384 | kfree(keypad); | ||
| 385 | return error; | ||
| 386 | } | ||
| 387 | |||
| 388 | static int __devexit tc3589x_keypad_remove(struct platform_device *pdev) | ||
| 389 | { | ||
| 390 | struct tc_keypad *keypad = platform_get_drvdata(pdev); | ||
| 391 | int irq = platform_get_irq(pdev, 0); | ||
| 392 | |||
| 393 | if (!keypad->keypad_stopped) | ||
| 394 | tc3589x_keypad_disable(keypad); | ||
| 395 | |||
| 396 | free_irq(irq, keypad); | ||
| 397 | |||
| 398 | input_unregister_device(keypad->input); | ||
| 399 | |||
| 400 | kfree(keypad); | ||
| 401 | |||
| 402 | return 0; | ||
| 403 | } | ||
| 404 | |||
| 405 | #ifdef CONFIG_PM | ||
| 406 | static int tc3589x_keypad_suspend(struct device *dev) | ||
| 407 | { | ||
| 408 | struct platform_device *pdev = to_platform_device(dev); | ||
| 409 | struct tc_keypad *keypad = platform_get_drvdata(pdev); | ||
| 410 | int irq = platform_get_irq(pdev, 0); | ||
| 411 | |||
| 412 | /* keypad is already off; we do nothing */ | ||
| 413 | if (keypad->keypad_stopped) | ||
| 414 | return 0; | ||
| 415 | |||
| 416 | /* if device is not a wakeup source, disable it for powersave */ | ||
| 417 | if (!device_may_wakeup(&pdev->dev)) | ||
| 418 | tc3589x_keypad_disable(keypad); | ||
| 419 | else | ||
| 420 | enable_irq_wake(irq); | ||
| 421 | |||
| 422 | return 0; | ||
| 423 | } | ||
| 424 | |||
| 425 | static int tc3589x_keypad_resume(struct device *dev) | ||
| 426 | { | ||
| 427 | struct platform_device *pdev = to_platform_device(dev); | ||
| 428 | struct tc_keypad *keypad = platform_get_drvdata(pdev); | ||
| 429 | int irq = platform_get_irq(pdev, 0); | ||
| 430 | |||
| 431 | if (!keypad->keypad_stopped) | ||
| 432 | return 0; | ||
| 433 | |||
| 434 | /* enable the device to resume normal operations */ | ||
| 435 | if (!device_may_wakeup(&pdev->dev)) | ||
| 436 | tc3589x_keypad_enable(keypad); | ||
| 437 | else | ||
| 438 | disable_irq_wake(irq); | ||
| 439 | |||
| 440 | return 0; | ||
| 441 | } | ||
| 442 | |||
| 443 | static const SIMPLE_DEV_PM_OPS(tc3589x_keypad_dev_pm_ops, | ||
| 444 | tc3589x_keypad_suspend, tc3589x_keypad_resume); | ||
| 445 | #endif | ||
| 446 | |||
| 447 | static struct platform_driver tc3589x_keypad_driver = { | ||
| 448 | .driver.name = "tc3589x-keypad", | ||
| 449 | .driver.owner = THIS_MODULE, | ||
| 450 | #ifdef CONFIG_PM | ||
| 451 | .driver.pm = &tc3589x_keypad_dev_pm_ops, | ||
| 452 | #endif | ||
| 453 | .probe = tc3589x_keypad_probe, | ||
| 454 | .remove = __devexit_p(tc3589x_keypad_remove), | ||
| 455 | }; | ||
| 456 | |||
| 457 | static int __init tc3589x_keypad_init(void) | ||
| 458 | { | ||
| 459 | return platform_driver_register(&tc3589x_keypad_driver); | ||
| 460 | } | ||
| 461 | module_init(tc3589x_keypad_init); | ||
| 462 | |||
| 463 | static void __exit tc3589x_keypad_exit(void) | ||
| 464 | { | ||
| 465 | return platform_driver_unregister(&tc3589x_keypad_driver); | ||
| 466 | } | ||
| 467 | module_exit(tc3589x_keypad_exit); | ||
| 468 | |||
| 469 | MODULE_LICENSE("GPL v2"); | ||
| 470 | MODULE_AUTHOR("Jayeeta Banerjee/Sundar Iyer"); | ||
| 471 | MODULE_DESCRIPTION("TC35893 Keypad Driver"); | ||
| 472 | MODULE_ALIAS("platform:tc3589x-keypad") | ||
diff --git a/drivers/mfd/tc3589x.c b/drivers/mfd/tc3589x.c index 112efd3c4940..729dbeed2ce0 100644 --- a/drivers/mfd/tc3589x.c +++ b/drivers/mfd/tc3589x.c | |||
| @@ -132,6 +132,14 @@ static struct resource gpio_resources[] = { | |||
| 132 | }, | 132 | }, |
| 133 | }; | 133 | }; |
| 134 | 134 | ||
| 135 | static struct resource keypad_resources[] = { | ||
| 136 | { | ||
| 137 | .start = TC3589x_INT_KBDIRQ, | ||
| 138 | .end = TC3589x_INT_KBDIRQ, | ||
| 139 | .flags = IORESOURCE_IRQ, | ||
| 140 | }, | ||
| 141 | }; | ||
| 142 | |||
| 135 | static struct mfd_cell tc3589x_dev_gpio[] = { | 143 | static struct mfd_cell tc3589x_dev_gpio[] = { |
| 136 | { | 144 | { |
| 137 | .name = "tc3589x-gpio", | 145 | .name = "tc3589x-gpio", |
| @@ -140,6 +148,14 @@ static struct mfd_cell tc3589x_dev_gpio[] = { | |||
| 140 | }, | 148 | }, |
| 141 | }; | 149 | }; |
| 142 | 150 | ||
| 151 | static struct mfd_cell tc3589x_dev_keypad[] = { | ||
| 152 | { | ||
| 153 | .name = "tc3589x-keypad", | ||
| 154 | .num_resources = ARRAY_SIZE(keypad_resources), | ||
| 155 | .resources = &keypad_resources[0], | ||
| 156 | }, | ||
| 157 | }; | ||
| 158 | |||
| 143 | static irqreturn_t tc3589x_irq(int irq, void *data) | 159 | static irqreturn_t tc3589x_irq(int irq, void *data) |
| 144 | { | 160 | { |
| 145 | struct tc3589x *tc3589x = data; | 161 | struct tc3589x *tc3589x = data; |
| @@ -255,8 +271,18 @@ static int __devinit tc3589x_device_init(struct tc3589x *tc3589x) | |||
| 255 | dev_info(tc3589x->dev, "added gpio block\n"); | 271 | dev_info(tc3589x->dev, "added gpio block\n"); |
| 256 | } | 272 | } |
| 257 | 273 | ||
| 258 | return ret; | 274 | if (blocks & TC3589x_BLOCK_KEYPAD) { |
| 275 | ret = mfd_add_devices(tc3589x->dev, -1, tc3589x_dev_keypad, | ||
| 276 | ARRAY_SIZE(tc3589x_dev_keypad), NULL, | ||
| 277 | tc3589x->irq_base); | ||
| 278 | if (ret) { | ||
| 279 | dev_err(tc3589x->dev, "failed to keypad child\n"); | ||
| 280 | return ret; | ||
| 281 | } | ||
| 282 | dev_info(tc3589x->dev, "added keypad block\n"); | ||
| 283 | } | ||
| 259 | 284 | ||
| 285 | return ret; | ||
| 260 | } | 286 | } |
| 261 | 287 | ||
| 262 | static int __devinit tc3589x_probe(struct i2c_client *i2c, | 288 | static int __devinit tc3589x_probe(struct i2c_client *i2c, |
diff --git a/include/linux/mfd/tc3589x.h b/include/linux/mfd/tc3589x.h index da00958b12d9..16c76e124f9c 100644 --- a/include/linux/mfd/tc3589x.h +++ b/include/linux/mfd/tc3589x.h | |||
| @@ -20,6 +20,17 @@ enum tx3589x_block { | |||
| 20 | #define TC3589x_RSTCTRL_KBDRST (1 << 1) | 20 | #define TC3589x_RSTCTRL_KBDRST (1 << 1) |
| 21 | #define TC3589x_RSTCTRL_GPIRST (1 << 0) | 21 | #define TC3589x_RSTCTRL_GPIRST (1 << 0) |
| 22 | 22 | ||
| 23 | /* Keyboard Configuration Registers */ | ||
| 24 | #define TC3589x_KBDSETTLE_REG 0x01 | ||
| 25 | #define TC3589x_KBDBOUNCE 0x02 | ||
| 26 | #define TC3589x_KBDSIZE 0x03 | ||
| 27 | #define TC3589x_KBCFG_LSB 0x04 | ||
| 28 | #define TC3589x_KBCFG_MSB 0x05 | ||
| 29 | #define TC3589x_KBDIC 0x08 | ||
| 30 | #define TC3589x_KBDMSK 0x09 | ||
| 31 | #define TC3589x_EVTCODE_FIFO 0x10 | ||
| 32 | #define TC3589x_KBDMFS 0x8F | ||
| 33 | |||
| 23 | #define TC3589x_IRQST 0x91 | 34 | #define TC3589x_IRQST 0x91 |
| 24 | 35 | ||
| 25 | #define TC3589x_MANFCODE_MAGIC 0x03 | 36 | #define TC3589x_MANFCODE_MAGIC 0x03 |
| @@ -35,6 +46,14 @@ enum tx3589x_block { | |||
| 35 | #define TC3589x_EXTRSTN 0x83 | 46 | #define TC3589x_EXTRSTN 0x83 |
| 36 | #define TC3589x_RSTINTCLR 0x84 | 47 | #define TC3589x_RSTINTCLR 0x84 |
| 37 | 48 | ||
| 49 | /* Pull up/down configuration registers */ | ||
| 50 | #define TC3589x_IOCFG 0xA7 | ||
| 51 | #define TC3589x_IOPULLCFG0_LSB 0xAA | ||
| 52 | #define TC3589x_IOPULLCFG0_MSB 0xAB | ||
| 53 | #define TC3589x_IOPULLCFG1_LSB 0xAC | ||
| 54 | #define TC3589x_IOPULLCFG1_MSB 0xAD | ||
| 55 | #define TC3589x_IOPULLCFG2_LSB 0xAE | ||
| 56 | |||
| 38 | #define TC3589x_GPIOIS0 0xC9 | 57 | #define TC3589x_GPIOIS0 0xC9 |
| 39 | #define TC3589x_GPIOIS1 0xCA | 58 | #define TC3589x_GPIOIS1 0xCA |
| 40 | #define TC3589x_GPIOIS2 0xCB | 59 | #define TC3589x_GPIOIS2 0xCB |
| @@ -112,6 +131,37 @@ extern int tc3589x_block_write(struct tc3589x *tc3589x, u8 reg, u8 length, | |||
| 112 | const u8 *values); | 131 | const u8 *values); |
| 113 | extern int tc3589x_set_bits(struct tc3589x *tc3589x, u8 reg, u8 mask, u8 val); | 132 | extern int tc3589x_set_bits(struct tc3589x *tc3589x, u8 reg, u8 mask, u8 val); |
| 114 | 133 | ||
| 134 | /* | ||
| 135 | * Keypad related platform specific constants | ||
| 136 | * These values may be modified for fine tuning | ||
| 137 | */ | ||
| 138 | #define TC_KPD_ROWS 0x8 | ||
| 139 | #define TC_KPD_COLUMNS 0x8 | ||
| 140 | #define TC_KPD_DEBOUNCE_PERIOD 0xA3 | ||
| 141 | #define TC_KPD_SETTLE_TIME 0xA3 | ||
| 142 | |||
| 143 | /** | ||
| 144 | * struct tc35893_platform_data - data structure for platform specific data | ||
| 145 | * @keymap_data: matrix scan code table for keycodes | ||
| 146 | * @krow: mask for available rows, value is 0xFF | ||
| 147 | * @kcol: mask for available columns, value is 0xFF | ||
| 148 | * @debounce_period: platform specific debounce time | ||
| 149 | * @settle_time: platform specific settle down time | ||
| 150 | * @irqtype: type of interrupt, falling or rising edge | ||
| 151 | * @enable_wakeup: specifies if keypad event can wake up system from sleep | ||
| 152 | * @no_autorepeat: flag for auto repetition | ||
| 153 | */ | ||
| 154 | struct tc3589x_keypad_platform_data { | ||
| 155 | const struct matrix_keymap_data *keymap_data; | ||
| 156 | u8 krow; | ||
| 157 | u8 kcol; | ||
| 158 | u8 debounce_period; | ||
| 159 | u8 settle_time; | ||
| 160 | unsigned long irqtype; | ||
| 161 | bool enable_wakeup; | ||
| 162 | bool no_autorepeat; | ||
| 163 | }; | ||
| 164 | |||
| 115 | /** | 165 | /** |
| 116 | * struct tc3589x_gpio_platform_data - TC3589x GPIO platform data | 166 | * struct tc3589x_gpio_platform_data - TC3589x GPIO platform data |
| 117 | * @gpio_base: first gpio number assigned to TC3589x. A maximum of | 167 | * @gpio_base: first gpio number assigned to TC3589x. A maximum of |
| @@ -130,11 +180,13 @@ struct tc3589x_gpio_platform_data { | |||
| 130 | * @block: bitmask of blocks to enable (use TC3589x_BLOCK_*) | 180 | * @block: bitmask of blocks to enable (use TC3589x_BLOCK_*) |
| 131 | * @irq_base: base IRQ number. %TC3589x_NR_IRQS irqs will be used. | 181 | * @irq_base: base IRQ number. %TC3589x_NR_IRQS irqs will be used. |
| 132 | * @gpio: GPIO-specific platform data | 182 | * @gpio: GPIO-specific platform data |
| 183 | * @keypad: keypad-specific platform data | ||
| 133 | */ | 184 | */ |
| 134 | struct tc3589x_platform_data { | 185 | struct tc3589x_platform_data { |
| 135 | unsigned int block; | 186 | unsigned int block; |
| 136 | int irq_base; | 187 | int irq_base; |
| 137 | struct tc3589x_gpio_platform_data *gpio; | 188 | struct tc3589x_gpio_platform_data *gpio; |
| 189 | const struct tc3589x_keypad_platform_data *keypad; | ||
| 138 | }; | 190 | }; |
| 139 | 191 | ||
| 140 | #define TC3589x_NR_GPIOS 24 | 192 | #define TC3589x_NR_GPIOS 24 |
