139325b59STrilok Soni /* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved. 239325b59STrilok Soni * 339325b59STrilok Soni * This program is free software; you can redistribute it and/or modify 439325b59STrilok Soni * it under the terms of the GNU General Public License version 2 and 539325b59STrilok Soni * only version 2 as published by the Free Software Foundation. 639325b59STrilok Soni * 739325b59STrilok Soni * This program is distributed in the hope that it will be useful, 839325b59STrilok Soni * but WITHOUT ANY WARRANTY; without even the implied warranty of 939325b59STrilok Soni * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1039325b59STrilok Soni * GNU General Public License for more details. 1139325b59STrilok Soni */ 1239325b59STrilok Soni 1339325b59STrilok Soni #include <linux/module.h> 1439325b59STrilok Soni #include <linux/platform_device.h> 1539325b59STrilok Soni #include <linux/kernel.h> 1639325b59STrilok Soni #include <linux/interrupt.h> 1739325b59STrilok Soni #include <linux/slab.h> 1839325b59STrilok Soni #include <linux/input.h> 1939325b59STrilok Soni #include <linux/bitops.h> 2039325b59STrilok Soni #include <linux/delay.h> 2139325b59STrilok Soni #include <linux/mutex.h> 22a5dde0c7SStephen Boyd #include <linux/regmap.h> 2386ea5e6bSStephen Boyd #include <linux/of.h> 2486ea5e6bSStephen Boyd #include <linux/input/matrix_keypad.h> 2539325b59STrilok Soni 2639325b59STrilok Soni #define PM8XXX_MAX_ROWS 18 2739325b59STrilok Soni #define PM8XXX_MAX_COLS 8 2839325b59STrilok Soni #define PM8XXX_ROW_SHIFT 3 2939325b59STrilok Soni #define PM8XXX_MATRIX_MAX_SIZE (PM8XXX_MAX_ROWS * PM8XXX_MAX_COLS) 3039325b59STrilok Soni 3139325b59STrilok Soni #define PM8XXX_MIN_ROWS 5 3239325b59STrilok Soni #define PM8XXX_MIN_COLS 5 3339325b59STrilok Soni 3439325b59STrilok Soni #define MAX_SCAN_DELAY 128 3539325b59STrilok Soni #define MIN_SCAN_DELAY 1 3639325b59STrilok Soni 3739325b59STrilok Soni /* in nanoseconds */ 3839325b59STrilok Soni #define MAX_ROW_HOLD_DELAY 122000 3939325b59STrilok Soni #define MIN_ROW_HOLD_DELAY 30500 4039325b59STrilok Soni 4139325b59STrilok Soni #define MAX_DEBOUNCE_TIME 20 4239325b59STrilok Soni #define MIN_DEBOUNCE_TIME 5 4339325b59STrilok Soni 4439325b59STrilok Soni #define KEYP_CTRL 0x148 4539325b59STrilok Soni 4639325b59STrilok Soni #define KEYP_CTRL_EVNTS BIT(0) 4739325b59STrilok Soni #define KEYP_CTRL_EVNTS_MASK 0x3 4839325b59STrilok Soni 4939325b59STrilok Soni #define KEYP_CTRL_SCAN_COLS_SHIFT 5 5039325b59STrilok Soni #define KEYP_CTRL_SCAN_COLS_MIN 5 5139325b59STrilok Soni #define KEYP_CTRL_SCAN_COLS_BITS 0x3 5239325b59STrilok Soni 5339325b59STrilok Soni #define KEYP_CTRL_SCAN_ROWS_SHIFT 2 5439325b59STrilok Soni #define KEYP_CTRL_SCAN_ROWS_MIN 5 5539325b59STrilok Soni #define KEYP_CTRL_SCAN_ROWS_BITS 0x7 5639325b59STrilok Soni 5739325b59STrilok Soni #define KEYP_CTRL_KEYP_EN BIT(7) 5839325b59STrilok Soni 5939325b59STrilok Soni #define KEYP_SCAN 0x149 6039325b59STrilok Soni 6139325b59STrilok Soni #define KEYP_SCAN_READ_STATE BIT(0) 6239325b59STrilok Soni #define KEYP_SCAN_DBOUNCE_SHIFT 1 6339325b59STrilok Soni #define KEYP_SCAN_PAUSE_SHIFT 3 6439325b59STrilok Soni #define KEYP_SCAN_ROW_HOLD_SHIFT 6 6539325b59STrilok Soni 6639325b59STrilok Soni #define KEYP_TEST 0x14A 6739325b59STrilok Soni 6839325b59STrilok Soni #define KEYP_TEST_CLEAR_RECENT_SCAN BIT(6) 6939325b59STrilok Soni #define KEYP_TEST_CLEAR_OLD_SCAN BIT(5) 7039325b59STrilok Soni #define KEYP_TEST_READ_RESET BIT(4) 7139325b59STrilok Soni #define KEYP_TEST_DTEST_EN BIT(3) 7239325b59STrilok Soni #define KEYP_TEST_ABORT_READ BIT(0) 7339325b59STrilok Soni 7439325b59STrilok Soni #define KEYP_TEST_DBG_SELECT_SHIFT 1 7539325b59STrilok Soni 7639325b59STrilok Soni /* bits of these registers represent 7739325b59STrilok Soni * '0' for key press 7839325b59STrilok Soni * '1' for key release 7939325b59STrilok Soni */ 8039325b59STrilok Soni #define KEYP_RECENT_DATA 0x14B 8139325b59STrilok Soni #define KEYP_OLD_DATA 0x14C 8239325b59STrilok Soni 8339325b59STrilok Soni #define KEYP_CLOCK_FREQ 32768 8439325b59STrilok Soni 8539325b59STrilok Soni /** 8639325b59STrilok Soni * struct pmic8xxx_kp - internal keypad data structure 8786ea5e6bSStephen Boyd * @num_cols - number of columns of keypad 8886ea5e6bSStephen Boyd * @num_rows - number of row of keypad 8939325b59STrilok Soni * @input - input device pointer for keypad 90a5dde0c7SStephen Boyd * @regmap - regmap handle 9139325b59STrilok Soni * @key_sense_irq - key press/release irq number 9239325b59STrilok Soni * @key_stuck_irq - key stuck notification irq number 9339325b59STrilok Soni * @keycodes - array to hold the key codes 9439325b59STrilok Soni * @dev - parent device pointer 9539325b59STrilok Soni * @keystate - present key press/release state 9639325b59STrilok Soni * @stuckstate - present state when key stuck irq 9739325b59STrilok Soni * @ctrl_reg - control register value 9839325b59STrilok Soni */ 9939325b59STrilok Soni struct pmic8xxx_kp { 10086ea5e6bSStephen Boyd unsigned int num_rows; 10186ea5e6bSStephen Boyd unsigned int num_cols; 10239325b59STrilok Soni struct input_dev *input; 103a5dde0c7SStephen Boyd struct regmap *regmap; 10439325b59STrilok Soni int key_sense_irq; 10539325b59STrilok Soni int key_stuck_irq; 10639325b59STrilok Soni 10739325b59STrilok Soni unsigned short keycodes[PM8XXX_MATRIX_MAX_SIZE]; 10839325b59STrilok Soni 10939325b59STrilok Soni struct device *dev; 11039325b59STrilok Soni u16 keystate[PM8XXX_MAX_ROWS]; 11139325b59STrilok Soni u16 stuckstate[PM8XXX_MAX_ROWS]; 11239325b59STrilok Soni 11339325b59STrilok Soni u8 ctrl_reg; 11439325b59STrilok Soni }; 11539325b59STrilok Soni 11639325b59STrilok Soni static u8 pmic8xxx_col_state(struct pmic8xxx_kp *kp, u8 col) 11739325b59STrilok Soni { 11839325b59STrilok Soni /* all keys pressed on that particular row? */ 11939325b59STrilok Soni if (col == 0x00) 12086ea5e6bSStephen Boyd return 1 << kp->num_cols; 12139325b59STrilok Soni else 12286ea5e6bSStephen Boyd return col & ((1 << kp->num_cols) - 1); 12339325b59STrilok Soni } 12439325b59STrilok Soni 12539325b59STrilok Soni /* 12639325b59STrilok Soni * Synchronous read protocol for RevB0 onwards: 12739325b59STrilok Soni * 12839325b59STrilok Soni * 1. Write '1' to ReadState bit in KEYP_SCAN register 12939325b59STrilok Soni * 2. Wait 2*32KHz clocks, so that HW can successfully enter read mode 13039325b59STrilok Soni * synchronously 13139325b59STrilok Soni * 3. Read rows in old array first if events are more than one 13239325b59STrilok Soni * 4. Read rows in recent array 13339325b59STrilok Soni * 5. Wait 4*32KHz clocks 13439325b59STrilok Soni * 6. Write '0' to ReadState bit of KEYP_SCAN register so that hw can 13539325b59STrilok Soni * synchronously exit read mode. 13639325b59STrilok Soni */ 13739325b59STrilok Soni static int pmic8xxx_chk_sync_read(struct pmic8xxx_kp *kp) 13839325b59STrilok Soni { 13939325b59STrilok Soni int rc; 140a5dde0c7SStephen Boyd unsigned int scan_val; 14139325b59STrilok Soni 142a5dde0c7SStephen Boyd rc = regmap_read(kp->regmap, KEYP_SCAN, &scan_val); 14339325b59STrilok Soni if (rc < 0) { 14439325b59STrilok Soni dev_err(kp->dev, "Error reading KEYP_SCAN reg, rc=%d\n", rc); 14539325b59STrilok Soni return rc; 14639325b59STrilok Soni } 14739325b59STrilok Soni 14839325b59STrilok Soni scan_val |= 0x1; 14939325b59STrilok Soni 150a5dde0c7SStephen Boyd rc = regmap_write(kp->regmap, KEYP_SCAN, scan_val); 15139325b59STrilok Soni if (rc < 0) { 15239325b59STrilok Soni dev_err(kp->dev, "Error writing KEYP_SCAN reg, rc=%d\n", rc); 15339325b59STrilok Soni return rc; 15439325b59STrilok Soni } 15539325b59STrilok Soni 15639325b59STrilok Soni /* 2 * 32KHz clocks */ 15739325b59STrilok Soni udelay((2 * DIV_ROUND_UP(USEC_PER_SEC, KEYP_CLOCK_FREQ)) + 1); 15839325b59STrilok Soni 15939325b59STrilok Soni return rc; 16039325b59STrilok Soni } 16139325b59STrilok Soni 16239325b59STrilok Soni static int pmic8xxx_kp_read_data(struct pmic8xxx_kp *kp, u16 *state, 16339325b59STrilok Soni u16 data_reg, int read_rows) 16439325b59STrilok Soni { 16539325b59STrilok Soni int rc, row; 166a5dde0c7SStephen Boyd unsigned int val; 16739325b59STrilok Soni 168a5dde0c7SStephen Boyd for (row = 0; row < read_rows; row++) { 169a5dde0c7SStephen Boyd rc = regmap_read(kp->regmap, data_reg, &val); 17039325b59STrilok Soni if (rc) 17139325b59STrilok Soni return rc; 172a5dde0c7SStephen Boyd dev_dbg(kp->dev, "%d = %d\n", row, val); 173a5dde0c7SStephen Boyd state[row] = pmic8xxx_col_state(kp, val); 17439325b59STrilok Soni } 17539325b59STrilok Soni 176a5dde0c7SStephen Boyd return 0; 17739325b59STrilok Soni } 17839325b59STrilok Soni 17939325b59STrilok Soni static int pmic8xxx_kp_read_matrix(struct pmic8xxx_kp *kp, u16 *new_state, 18039325b59STrilok Soni u16 *old_state) 18139325b59STrilok Soni { 18239325b59STrilok Soni int rc, read_rows; 183a5dde0c7SStephen Boyd unsigned int scan_val; 18439325b59STrilok Soni 18586ea5e6bSStephen Boyd if (kp->num_rows < PM8XXX_MIN_ROWS) 18639325b59STrilok Soni read_rows = PM8XXX_MIN_ROWS; 18739325b59STrilok Soni else 18886ea5e6bSStephen Boyd read_rows = kp->num_rows; 18939325b59STrilok Soni 19039325b59STrilok Soni pmic8xxx_chk_sync_read(kp); 19139325b59STrilok Soni 19239325b59STrilok Soni if (old_state) { 19339325b59STrilok Soni rc = pmic8xxx_kp_read_data(kp, old_state, KEYP_OLD_DATA, 19439325b59STrilok Soni read_rows); 19539325b59STrilok Soni if (rc < 0) { 19639325b59STrilok Soni dev_err(kp->dev, 19739325b59STrilok Soni "Error reading KEYP_OLD_DATA, rc=%d\n", rc); 19839325b59STrilok Soni return rc; 19939325b59STrilok Soni } 20039325b59STrilok Soni } 20139325b59STrilok Soni 20239325b59STrilok Soni rc = pmic8xxx_kp_read_data(kp, new_state, KEYP_RECENT_DATA, 20339325b59STrilok Soni read_rows); 20439325b59STrilok Soni if (rc < 0) { 20539325b59STrilok Soni dev_err(kp->dev, 20639325b59STrilok Soni "Error reading KEYP_RECENT_DATA, rc=%d\n", rc); 20739325b59STrilok Soni return rc; 20839325b59STrilok Soni } 20939325b59STrilok Soni 21039325b59STrilok Soni /* 4 * 32KHz clocks */ 21139325b59STrilok Soni udelay((4 * DIV_ROUND_UP(USEC_PER_SEC, KEYP_CLOCK_FREQ)) + 1); 21239325b59STrilok Soni 213a5dde0c7SStephen Boyd rc = regmap_read(kp->regmap, KEYP_SCAN, &scan_val); 21439325b59STrilok Soni if (rc < 0) { 21539325b59STrilok Soni dev_err(kp->dev, "Error reading KEYP_SCAN reg, rc=%d\n", rc); 21639325b59STrilok Soni return rc; 21739325b59STrilok Soni } 21839325b59STrilok Soni 21939325b59STrilok Soni scan_val &= 0xFE; 220a5dde0c7SStephen Boyd rc = regmap_write(kp->regmap, KEYP_SCAN, scan_val); 22139325b59STrilok Soni if (rc < 0) 22239325b59STrilok Soni dev_err(kp->dev, "Error writing KEYP_SCAN reg, rc=%d\n", rc); 22339325b59STrilok Soni 22439325b59STrilok Soni return rc; 22539325b59STrilok Soni } 22639325b59STrilok Soni 22739325b59STrilok Soni static void __pmic8xxx_kp_scan_matrix(struct pmic8xxx_kp *kp, u16 *new_state, 22839325b59STrilok Soni u16 *old_state) 22939325b59STrilok Soni { 23039325b59STrilok Soni int row, col, code; 23139325b59STrilok Soni 23286ea5e6bSStephen Boyd for (row = 0; row < kp->num_rows; row++) { 23339325b59STrilok Soni int bits_changed = new_state[row] ^ old_state[row]; 23439325b59STrilok Soni 23539325b59STrilok Soni if (!bits_changed) 23639325b59STrilok Soni continue; 23739325b59STrilok Soni 23886ea5e6bSStephen Boyd for (col = 0; col < kp->num_cols; col++) { 23939325b59STrilok Soni if (!(bits_changed & (1 << col))) 24039325b59STrilok Soni continue; 24139325b59STrilok Soni 24239325b59STrilok Soni dev_dbg(kp->dev, "key [%d:%d] %s\n", row, col, 24339325b59STrilok Soni !(new_state[row] & (1 << col)) ? 24439325b59STrilok Soni "pressed" : "released"); 24539325b59STrilok Soni 24639325b59STrilok Soni code = MATRIX_SCAN_CODE(row, col, PM8XXX_ROW_SHIFT); 24739325b59STrilok Soni 24839325b59STrilok Soni input_event(kp->input, EV_MSC, MSC_SCAN, code); 24939325b59STrilok Soni input_report_key(kp->input, 25039325b59STrilok Soni kp->keycodes[code], 25139325b59STrilok Soni !(new_state[row] & (1 << col))); 25239325b59STrilok Soni 25339325b59STrilok Soni input_sync(kp->input); 25439325b59STrilok Soni } 25539325b59STrilok Soni } 25639325b59STrilok Soni } 25739325b59STrilok Soni 25839325b59STrilok Soni static bool pmic8xxx_detect_ghost_keys(struct pmic8xxx_kp *kp, u16 *new_state) 25939325b59STrilok Soni { 26039325b59STrilok Soni int row, found_first = -1; 26139325b59STrilok Soni u16 check, row_state; 26239325b59STrilok Soni 26339325b59STrilok Soni check = 0; 26486ea5e6bSStephen Boyd for (row = 0; row < kp->num_rows; row++) { 26539325b59STrilok Soni row_state = (~new_state[row]) & 26686ea5e6bSStephen Boyd ((1 << kp->num_cols) - 1); 26739325b59STrilok Soni 26839325b59STrilok Soni if (hweight16(row_state) > 1) { 26939325b59STrilok Soni if (found_first == -1) 27039325b59STrilok Soni found_first = row; 27139325b59STrilok Soni if (check & row_state) { 27239325b59STrilok Soni dev_dbg(kp->dev, "detected ghost key on row[%d]" 27339325b59STrilok Soni " and row[%d]\n", found_first, row); 27439325b59STrilok Soni return true; 27539325b59STrilok Soni } 27639325b59STrilok Soni } 27739325b59STrilok Soni check |= row_state; 27839325b59STrilok Soni } 27939325b59STrilok Soni return false; 28039325b59STrilok Soni } 28139325b59STrilok Soni 28239325b59STrilok Soni static int pmic8xxx_kp_scan_matrix(struct pmic8xxx_kp *kp, unsigned int events) 28339325b59STrilok Soni { 28439325b59STrilok Soni u16 new_state[PM8XXX_MAX_ROWS]; 28539325b59STrilok Soni u16 old_state[PM8XXX_MAX_ROWS]; 28639325b59STrilok Soni int rc; 28739325b59STrilok Soni 28839325b59STrilok Soni switch (events) { 28939325b59STrilok Soni case 0x1: 29039325b59STrilok Soni rc = pmic8xxx_kp_read_matrix(kp, new_state, NULL); 29139325b59STrilok Soni if (rc < 0) 29239325b59STrilok Soni return rc; 29339325b59STrilok Soni 29439325b59STrilok Soni /* detecting ghost key is not an error */ 29539325b59STrilok Soni if (pmic8xxx_detect_ghost_keys(kp, new_state)) 29639325b59STrilok Soni return 0; 29739325b59STrilok Soni __pmic8xxx_kp_scan_matrix(kp, new_state, kp->keystate); 29839325b59STrilok Soni memcpy(kp->keystate, new_state, sizeof(new_state)); 29939325b59STrilok Soni break; 30039325b59STrilok Soni case 0x3: /* two events - eventcounter is gray-coded */ 30139325b59STrilok Soni rc = pmic8xxx_kp_read_matrix(kp, new_state, old_state); 30239325b59STrilok Soni if (rc < 0) 30339325b59STrilok Soni return rc; 30439325b59STrilok Soni 30539325b59STrilok Soni __pmic8xxx_kp_scan_matrix(kp, old_state, kp->keystate); 30639325b59STrilok Soni __pmic8xxx_kp_scan_matrix(kp, new_state, old_state); 30739325b59STrilok Soni memcpy(kp->keystate, new_state, sizeof(new_state)); 30839325b59STrilok Soni break; 30939325b59STrilok Soni case 0x2: 31039325b59STrilok Soni dev_dbg(kp->dev, "Some key events were lost\n"); 31139325b59STrilok Soni rc = pmic8xxx_kp_read_matrix(kp, new_state, old_state); 31239325b59STrilok Soni if (rc < 0) 31339325b59STrilok Soni return rc; 31439325b59STrilok Soni __pmic8xxx_kp_scan_matrix(kp, old_state, kp->keystate); 31539325b59STrilok Soni __pmic8xxx_kp_scan_matrix(kp, new_state, old_state); 31639325b59STrilok Soni memcpy(kp->keystate, new_state, sizeof(new_state)); 31739325b59STrilok Soni break; 31839325b59STrilok Soni default: 31939325b59STrilok Soni rc = -EINVAL; 32039325b59STrilok Soni } 32139325b59STrilok Soni return rc; 32239325b59STrilok Soni } 32339325b59STrilok Soni 32439325b59STrilok Soni /* 32539325b59STrilok Soni * NOTE: We are reading recent and old data registers blindly 32639325b59STrilok Soni * whenever key-stuck interrupt happens, because events counter doesn't 32739325b59STrilok Soni * get updated when this interrupt happens due to key stuck doesn't get 32839325b59STrilok Soni * considered as key state change. 32939325b59STrilok Soni * 33039325b59STrilok Soni * We are not using old data register contents after they are being read 33139325b59STrilok Soni * because it might report the key which was pressed before the key being stuck 33239325b59STrilok Soni * as stuck key because it's pressed status is stored in the old data 33339325b59STrilok Soni * register. 33439325b59STrilok Soni */ 33539325b59STrilok Soni static irqreturn_t pmic8xxx_kp_stuck_irq(int irq, void *data) 33639325b59STrilok Soni { 33739325b59STrilok Soni u16 new_state[PM8XXX_MAX_ROWS]; 33839325b59STrilok Soni u16 old_state[PM8XXX_MAX_ROWS]; 33939325b59STrilok Soni int rc; 34039325b59STrilok Soni struct pmic8xxx_kp *kp = data; 34139325b59STrilok Soni 34239325b59STrilok Soni rc = pmic8xxx_kp_read_matrix(kp, new_state, old_state); 34339325b59STrilok Soni if (rc < 0) { 34439325b59STrilok Soni dev_err(kp->dev, "failed to read keypad matrix\n"); 34539325b59STrilok Soni return IRQ_HANDLED; 34639325b59STrilok Soni } 34739325b59STrilok Soni 34839325b59STrilok Soni __pmic8xxx_kp_scan_matrix(kp, new_state, kp->stuckstate); 34939325b59STrilok Soni 35039325b59STrilok Soni return IRQ_HANDLED; 35139325b59STrilok Soni } 35239325b59STrilok Soni 35339325b59STrilok Soni static irqreturn_t pmic8xxx_kp_irq(int irq, void *data) 35439325b59STrilok Soni { 35539325b59STrilok Soni struct pmic8xxx_kp *kp = data; 356a5dde0c7SStephen Boyd unsigned int ctrl_val, events; 35739325b59STrilok Soni int rc; 35839325b59STrilok Soni 359a5dde0c7SStephen Boyd rc = regmap_read(kp->regmap, KEYP_CTRL, &ctrl_val); 36039325b59STrilok Soni if (rc < 0) { 36139325b59STrilok Soni dev_err(kp->dev, "failed to read keyp_ctrl register\n"); 36239325b59STrilok Soni return IRQ_HANDLED; 36339325b59STrilok Soni } 36439325b59STrilok Soni 36539325b59STrilok Soni events = ctrl_val & KEYP_CTRL_EVNTS_MASK; 36639325b59STrilok Soni 36739325b59STrilok Soni rc = pmic8xxx_kp_scan_matrix(kp, events); 36839325b59STrilok Soni if (rc < 0) 36939325b59STrilok Soni dev_err(kp->dev, "failed to scan matrix\n"); 37039325b59STrilok Soni 37139325b59STrilok Soni return IRQ_HANDLED; 37239325b59STrilok Soni } 37339325b59STrilok Soni 37486ea5e6bSStephen Boyd static int pmic8xxx_kpd_init(struct pmic8xxx_kp *kp, 37586ea5e6bSStephen Boyd struct platform_device *pdev) 37639325b59STrilok Soni { 37786ea5e6bSStephen Boyd const struct device_node *of_node = pdev->dev.of_node; 37886ea5e6bSStephen Boyd unsigned int scan_delay_ms; 37986ea5e6bSStephen Boyd unsigned int row_hold_ns; 38086ea5e6bSStephen Boyd unsigned int debounce_ms; 38139325b59STrilok Soni int bits, rc, cycles; 38239325b59STrilok Soni u8 scan_val = 0, ctrl_val = 0; 38339325b59STrilok Soni static const u8 row_bits[] = { 38439325b59STrilok Soni 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 7, 7, 7, 38539325b59STrilok Soni }; 38639325b59STrilok Soni 38739325b59STrilok Soni /* Find column bits */ 38886ea5e6bSStephen Boyd if (kp->num_cols < KEYP_CTRL_SCAN_COLS_MIN) 38939325b59STrilok Soni bits = 0; 39039325b59STrilok Soni else 39186ea5e6bSStephen Boyd bits = kp->num_cols - KEYP_CTRL_SCAN_COLS_MIN; 39239325b59STrilok Soni ctrl_val = (bits & KEYP_CTRL_SCAN_COLS_BITS) << 39339325b59STrilok Soni KEYP_CTRL_SCAN_COLS_SHIFT; 39439325b59STrilok Soni 39539325b59STrilok Soni /* Find row bits */ 39686ea5e6bSStephen Boyd if (kp->num_rows < KEYP_CTRL_SCAN_ROWS_MIN) 39739325b59STrilok Soni bits = 0; 39839325b59STrilok Soni else 39986ea5e6bSStephen Boyd bits = row_bits[kp->num_rows - KEYP_CTRL_SCAN_ROWS_MIN]; 40039325b59STrilok Soni 40139325b59STrilok Soni ctrl_val |= (bits << KEYP_CTRL_SCAN_ROWS_SHIFT); 40239325b59STrilok Soni 403a5dde0c7SStephen Boyd rc = regmap_write(kp->regmap, KEYP_CTRL, ctrl_val); 40439325b59STrilok Soni if (rc < 0) { 40539325b59STrilok Soni dev_err(kp->dev, "Error writing KEYP_CTRL reg, rc=%d\n", rc); 40639325b59STrilok Soni return rc; 40739325b59STrilok Soni } 40839325b59STrilok Soni 40986ea5e6bSStephen Boyd if (of_property_read_u32(of_node, "scan-delay", &scan_delay_ms)) 41086ea5e6bSStephen Boyd scan_delay_ms = MIN_SCAN_DELAY; 41186ea5e6bSStephen Boyd 41286ea5e6bSStephen Boyd if (scan_delay_ms > MAX_SCAN_DELAY || scan_delay_ms < MIN_SCAN_DELAY || 41386ea5e6bSStephen Boyd !is_power_of_2(scan_delay_ms)) { 41486ea5e6bSStephen Boyd dev_err(&pdev->dev, "invalid keypad scan time supplied\n"); 41586ea5e6bSStephen Boyd return -EINVAL; 41686ea5e6bSStephen Boyd } 41786ea5e6bSStephen Boyd 41886ea5e6bSStephen Boyd if (of_property_read_u32(of_node, "row-hold", &row_hold_ns)) 41986ea5e6bSStephen Boyd row_hold_ns = MIN_ROW_HOLD_DELAY; 42086ea5e6bSStephen Boyd 42186ea5e6bSStephen Boyd if (row_hold_ns > MAX_ROW_HOLD_DELAY || 42286ea5e6bSStephen Boyd row_hold_ns < MIN_ROW_HOLD_DELAY || 42386ea5e6bSStephen Boyd ((row_hold_ns % MIN_ROW_HOLD_DELAY) != 0)) { 42486ea5e6bSStephen Boyd dev_err(&pdev->dev, "invalid keypad row hold time supplied\n"); 42586ea5e6bSStephen Boyd return -EINVAL; 42686ea5e6bSStephen Boyd } 42786ea5e6bSStephen Boyd 42886ea5e6bSStephen Boyd if (of_property_read_u32(of_node, "debounce", &debounce_ms)) 42986ea5e6bSStephen Boyd debounce_ms = MIN_DEBOUNCE_TIME; 43086ea5e6bSStephen Boyd 43186ea5e6bSStephen Boyd if (((debounce_ms % 5) != 0) || 43286ea5e6bSStephen Boyd debounce_ms > MAX_DEBOUNCE_TIME || 43386ea5e6bSStephen Boyd debounce_ms < MIN_DEBOUNCE_TIME) { 43486ea5e6bSStephen Boyd dev_err(&pdev->dev, "invalid debounce time supplied\n"); 43586ea5e6bSStephen Boyd return -EINVAL; 43686ea5e6bSStephen Boyd } 43786ea5e6bSStephen Boyd 43886ea5e6bSStephen Boyd bits = (debounce_ms / 5) - 1; 43939325b59STrilok Soni 44039325b59STrilok Soni scan_val |= (bits << KEYP_SCAN_DBOUNCE_SHIFT); 44139325b59STrilok Soni 44286ea5e6bSStephen Boyd bits = fls(scan_delay_ms) - 1; 44339325b59STrilok Soni scan_val |= (bits << KEYP_SCAN_PAUSE_SHIFT); 44439325b59STrilok Soni 44539325b59STrilok Soni /* Row hold time is a multiple of 32KHz cycles. */ 44686ea5e6bSStephen Boyd cycles = (row_hold_ns * KEYP_CLOCK_FREQ) / NSEC_PER_SEC; 44739325b59STrilok Soni 44839325b59STrilok Soni scan_val |= (cycles << KEYP_SCAN_ROW_HOLD_SHIFT); 44939325b59STrilok Soni 450a5dde0c7SStephen Boyd rc = regmap_write(kp->regmap, KEYP_SCAN, scan_val); 45139325b59STrilok Soni if (rc) 45239325b59STrilok Soni dev_err(kp->dev, "Error writing KEYP_SCAN reg, rc=%d\n", rc); 45339325b59STrilok Soni 45439325b59STrilok Soni return rc; 45539325b59STrilok Soni 45639325b59STrilok Soni } 45739325b59STrilok Soni 45839325b59STrilok Soni static int pmic8xxx_kp_enable(struct pmic8xxx_kp *kp) 45939325b59STrilok Soni { 46039325b59STrilok Soni int rc; 46139325b59STrilok Soni 46239325b59STrilok Soni kp->ctrl_reg |= KEYP_CTRL_KEYP_EN; 46339325b59STrilok Soni 464a5dde0c7SStephen Boyd rc = regmap_write(kp->regmap, KEYP_CTRL, kp->ctrl_reg); 46539325b59STrilok Soni if (rc < 0) 46639325b59STrilok Soni dev_err(kp->dev, "Error writing KEYP_CTRL reg, rc=%d\n", rc); 46739325b59STrilok Soni 46839325b59STrilok Soni return rc; 46939325b59STrilok Soni } 47039325b59STrilok Soni 47139325b59STrilok Soni static int pmic8xxx_kp_disable(struct pmic8xxx_kp *kp) 47239325b59STrilok Soni { 47339325b59STrilok Soni int rc; 47439325b59STrilok Soni 47539325b59STrilok Soni kp->ctrl_reg &= ~KEYP_CTRL_KEYP_EN; 47639325b59STrilok Soni 477a5dde0c7SStephen Boyd rc = regmap_write(kp->regmap, KEYP_CTRL, kp->ctrl_reg); 47839325b59STrilok Soni if (rc < 0) 47939325b59STrilok Soni return rc; 48039325b59STrilok Soni 48139325b59STrilok Soni return rc; 48239325b59STrilok Soni } 48339325b59STrilok Soni 48439325b59STrilok Soni static int pmic8xxx_kp_open(struct input_dev *dev) 48539325b59STrilok Soni { 48639325b59STrilok Soni struct pmic8xxx_kp *kp = input_get_drvdata(dev); 48739325b59STrilok Soni 48839325b59STrilok Soni return pmic8xxx_kp_enable(kp); 48939325b59STrilok Soni } 49039325b59STrilok Soni 49139325b59STrilok Soni static void pmic8xxx_kp_close(struct input_dev *dev) 49239325b59STrilok Soni { 49339325b59STrilok Soni struct pmic8xxx_kp *kp = input_get_drvdata(dev); 49439325b59STrilok Soni 49539325b59STrilok Soni pmic8xxx_kp_disable(kp); 49639325b59STrilok Soni } 49739325b59STrilok Soni 49839325b59STrilok Soni /* 49939325b59STrilok Soni * keypad controller should be initialized in the following sequence 50039325b59STrilok Soni * only, otherwise it might get into FSM stuck state. 50139325b59STrilok Soni * 50239325b59STrilok Soni * - Initialize keypad control parameters, like no. of rows, columns, 50339325b59STrilok Soni * timing values etc., 50439325b59STrilok Soni * - configure rows and column gpios pull up/down. 50539325b59STrilok Soni * - set irq edge type. 50639325b59STrilok Soni * - enable the keypad controller. 50739325b59STrilok Soni */ 5085298cc4cSBill Pemberton static int pmic8xxx_kp_probe(struct platform_device *pdev) 50939325b59STrilok Soni { 51027469652SDmitry Torokhov struct device_node *np = pdev->dev.of_node; 51186ea5e6bSStephen Boyd unsigned int rows, cols; 51286ea5e6bSStephen Boyd bool repeat; 51386ea5e6bSStephen Boyd bool wakeup; 51439325b59STrilok Soni struct pmic8xxx_kp *kp; 51539325b59STrilok Soni int rc; 516a5dde0c7SStephen Boyd unsigned int ctrl_val; 51739325b59STrilok Soni 518*aef01aadSDmitry Torokhov rc = matrix_keypad_parse_properties(&pdev->dev, &rows, &cols); 51986ea5e6bSStephen Boyd if (rc) 52086ea5e6bSStephen Boyd return rc; 52186ea5e6bSStephen Boyd 52286ea5e6bSStephen Boyd if (cols > PM8XXX_MAX_COLS || rows > PM8XXX_MAX_ROWS || 52386ea5e6bSStephen Boyd cols < PM8XXX_MIN_COLS) { 52439325b59STrilok Soni dev_err(&pdev->dev, "invalid platform data\n"); 52539325b59STrilok Soni return -EINVAL; 52639325b59STrilok Soni } 52739325b59STrilok Soni 52827469652SDmitry Torokhov repeat = !of_property_read_bool(np, "linux,input-no-autorepeat"); 52927469652SDmitry Torokhov 53027469652SDmitry Torokhov wakeup = of_property_read_bool(np, "wakeup-source") || 53127469652SDmitry Torokhov /* legacy name */ 53227469652SDmitry Torokhov of_property_read_bool(np, "linux,keypad-wakeup"); 53339325b59STrilok Soni 534c7f6ee26SStephen Boyd kp = devm_kzalloc(&pdev->dev, sizeof(*kp), GFP_KERNEL); 53539325b59STrilok Soni if (!kp) 53639325b59STrilok Soni return -ENOMEM; 53739325b59STrilok Soni 538a5dde0c7SStephen Boyd kp->regmap = dev_get_regmap(pdev->dev.parent, NULL); 539a5dde0c7SStephen Boyd if (!kp->regmap) 540a5dde0c7SStephen Boyd return -ENODEV; 541a5dde0c7SStephen Boyd 54239325b59STrilok Soni platform_set_drvdata(pdev, kp); 54339325b59STrilok Soni 54486ea5e6bSStephen Boyd kp->num_rows = rows; 54586ea5e6bSStephen Boyd kp->num_cols = cols; 54639325b59STrilok Soni kp->dev = &pdev->dev; 54739325b59STrilok Soni 548c7f6ee26SStephen Boyd kp->input = devm_input_allocate_device(&pdev->dev); 54939325b59STrilok Soni if (!kp->input) { 55039325b59STrilok Soni dev_err(&pdev->dev, "unable to allocate input device\n"); 551c7f6ee26SStephen Boyd return -ENOMEM; 55239325b59STrilok Soni } 55339325b59STrilok Soni 55439325b59STrilok Soni kp->key_sense_irq = platform_get_irq(pdev, 0); 55539325b59STrilok Soni if (kp->key_sense_irq < 0) { 55639325b59STrilok Soni dev_err(&pdev->dev, "unable to get keypad sense irq\n"); 557c7f6ee26SStephen Boyd return kp->key_sense_irq; 55839325b59STrilok Soni } 55939325b59STrilok Soni 56039325b59STrilok Soni kp->key_stuck_irq = platform_get_irq(pdev, 1); 56139325b59STrilok Soni if (kp->key_stuck_irq < 0) { 56239325b59STrilok Soni dev_err(&pdev->dev, "unable to get keypad stuck irq\n"); 563c7f6ee26SStephen Boyd return kp->key_stuck_irq; 56439325b59STrilok Soni } 56539325b59STrilok Soni 56686ea5e6bSStephen Boyd kp->input->name = "PMIC8XXX keypad"; 56786ea5e6bSStephen Boyd kp->input->phys = "pmic8xxx_keypad/input0"; 56839325b59STrilok Soni 56939325b59STrilok Soni kp->input->id.bustype = BUS_I2C; 57039325b59STrilok Soni kp->input->id.version = 0x0001; 57139325b59STrilok Soni kp->input->id.product = 0x0001; 57239325b59STrilok Soni kp->input->id.vendor = 0x0001; 57339325b59STrilok Soni 57439325b59STrilok Soni kp->input->open = pmic8xxx_kp_open; 57539325b59STrilok Soni kp->input->close = pmic8xxx_kp_close; 57639325b59STrilok Soni 57786ea5e6bSStephen Boyd rc = matrix_keypad_build_keymap(NULL, NULL, 5781932811fSDmitry Torokhov PM8XXX_MAX_ROWS, PM8XXX_MAX_COLS, 5791932811fSDmitry Torokhov kp->keycodes, kp->input); 5801932811fSDmitry Torokhov if (rc) { 5811932811fSDmitry Torokhov dev_err(&pdev->dev, "failed to build keymap\n"); 582c7f6ee26SStephen Boyd return rc; 5831932811fSDmitry Torokhov } 58439325b59STrilok Soni 58586ea5e6bSStephen Boyd if (repeat) 5861932811fSDmitry Torokhov __set_bit(EV_REP, kp->input->evbit); 58739325b59STrilok Soni input_set_capability(kp->input, EV_MSC, MSC_SCAN); 5881932811fSDmitry Torokhov 58939325b59STrilok Soni input_set_drvdata(kp->input, kp); 59039325b59STrilok Soni 59139325b59STrilok Soni /* initialize keypad state */ 59239325b59STrilok Soni memset(kp->keystate, 0xff, sizeof(kp->keystate)); 59339325b59STrilok Soni memset(kp->stuckstate, 0xff, sizeof(kp->stuckstate)); 59439325b59STrilok Soni 59586ea5e6bSStephen Boyd rc = pmic8xxx_kpd_init(kp, pdev); 59639325b59STrilok Soni if (rc < 0) { 59739325b59STrilok Soni dev_err(&pdev->dev, "unable to initialize keypad controller\n"); 598c7f6ee26SStephen Boyd return rc; 59939325b59STrilok Soni } 60039325b59STrilok Soni 601c7f6ee26SStephen Boyd rc = devm_request_any_context_irq(&pdev->dev, kp->key_sense_irq, 602c7f6ee26SStephen Boyd pmic8xxx_kp_irq, IRQF_TRIGGER_RISING, "pmic-keypad", 603c7f6ee26SStephen Boyd kp); 60439325b59STrilok Soni if (rc < 0) { 60539325b59STrilok Soni dev_err(&pdev->dev, "failed to request keypad sense irq\n"); 606c7f6ee26SStephen Boyd return rc; 60739325b59STrilok Soni } 60839325b59STrilok Soni 609c7f6ee26SStephen Boyd rc = devm_request_any_context_irq(&pdev->dev, kp->key_stuck_irq, 610c7f6ee26SStephen Boyd pmic8xxx_kp_stuck_irq, IRQF_TRIGGER_RISING, 611c7f6ee26SStephen Boyd "pmic-keypad-stuck", kp); 61239325b59STrilok Soni if (rc < 0) { 61339325b59STrilok Soni dev_err(&pdev->dev, "failed to request keypad stuck irq\n"); 614c7f6ee26SStephen Boyd return rc; 61539325b59STrilok Soni } 61639325b59STrilok Soni 617a5dde0c7SStephen Boyd rc = regmap_read(kp->regmap, KEYP_CTRL, &ctrl_val); 61839325b59STrilok Soni if (rc < 0) { 61939325b59STrilok Soni dev_err(&pdev->dev, "failed to read KEYP_CTRL register\n"); 620c7f6ee26SStephen Boyd return rc; 62139325b59STrilok Soni } 62239325b59STrilok Soni 62339325b59STrilok Soni kp->ctrl_reg = ctrl_val; 62439325b59STrilok Soni 62539325b59STrilok Soni rc = input_register_device(kp->input); 62639325b59STrilok Soni if (rc < 0) { 62739325b59STrilok Soni dev_err(&pdev->dev, "unable to register keypad input device\n"); 62839325b59STrilok Soni return rc; 62939325b59STrilok Soni } 63039325b59STrilok Soni 63186ea5e6bSStephen Boyd device_init_wakeup(&pdev->dev, wakeup); 63239325b59STrilok Soni 63339325b59STrilok Soni return 0; 63439325b59STrilok Soni } 63539325b59STrilok Soni 63639325b59STrilok Soni #ifdef CONFIG_PM_SLEEP 63739325b59STrilok Soni static int pmic8xxx_kp_suspend(struct device *dev) 63839325b59STrilok Soni { 63939325b59STrilok Soni struct platform_device *pdev = to_platform_device(dev); 64039325b59STrilok Soni struct pmic8xxx_kp *kp = platform_get_drvdata(pdev); 64139325b59STrilok Soni struct input_dev *input_dev = kp->input; 64239325b59STrilok Soni 64339325b59STrilok Soni if (device_may_wakeup(dev)) { 64439325b59STrilok Soni enable_irq_wake(kp->key_sense_irq); 64539325b59STrilok Soni } else { 64639325b59STrilok Soni mutex_lock(&input_dev->mutex); 64739325b59STrilok Soni 64839325b59STrilok Soni if (input_dev->users) 64939325b59STrilok Soni pmic8xxx_kp_disable(kp); 65039325b59STrilok Soni 65139325b59STrilok Soni mutex_unlock(&input_dev->mutex); 65239325b59STrilok Soni } 65339325b59STrilok Soni 65439325b59STrilok Soni return 0; 65539325b59STrilok Soni } 65639325b59STrilok Soni 65739325b59STrilok Soni static int pmic8xxx_kp_resume(struct device *dev) 65839325b59STrilok Soni { 65939325b59STrilok Soni struct platform_device *pdev = to_platform_device(dev); 66039325b59STrilok Soni struct pmic8xxx_kp *kp = platform_get_drvdata(pdev); 66139325b59STrilok Soni struct input_dev *input_dev = kp->input; 66239325b59STrilok Soni 66339325b59STrilok Soni if (device_may_wakeup(dev)) { 66439325b59STrilok Soni disable_irq_wake(kp->key_sense_irq); 66539325b59STrilok Soni } else { 66639325b59STrilok Soni mutex_lock(&input_dev->mutex); 66739325b59STrilok Soni 66839325b59STrilok Soni if (input_dev->users) 66939325b59STrilok Soni pmic8xxx_kp_enable(kp); 67039325b59STrilok Soni 67139325b59STrilok Soni mutex_unlock(&input_dev->mutex); 67239325b59STrilok Soni } 67339325b59STrilok Soni 67439325b59STrilok Soni return 0; 67539325b59STrilok Soni } 67639325b59STrilok Soni #endif 67739325b59STrilok Soni 67839325b59STrilok Soni static SIMPLE_DEV_PM_OPS(pm8xxx_kp_pm_ops, 67939325b59STrilok Soni pmic8xxx_kp_suspend, pmic8xxx_kp_resume); 68039325b59STrilok Soni 68186ea5e6bSStephen Boyd static const struct of_device_id pm8xxx_match_table[] = { 68286ea5e6bSStephen Boyd { .compatible = "qcom,pm8058-keypad" }, 68386ea5e6bSStephen Boyd { .compatible = "qcom,pm8921-keypad" }, 68486ea5e6bSStephen Boyd { } 68586ea5e6bSStephen Boyd }; 68686ea5e6bSStephen Boyd MODULE_DEVICE_TABLE(of, pm8xxx_match_table); 68786ea5e6bSStephen Boyd 68839325b59STrilok Soni static struct platform_driver pmic8xxx_kp_driver = { 68939325b59STrilok Soni .probe = pmic8xxx_kp_probe, 69039325b59STrilok Soni .driver = { 69186ea5e6bSStephen Boyd .name = "pm8xxx-keypad", 69239325b59STrilok Soni .pm = &pm8xxx_kp_pm_ops, 69386ea5e6bSStephen Boyd .of_match_table = pm8xxx_match_table, 69439325b59STrilok Soni }, 69539325b59STrilok Soni }; 6965146c84fSJJ Ding module_platform_driver(pmic8xxx_kp_driver); 69739325b59STrilok Soni 69839325b59STrilok Soni MODULE_LICENSE("GPL v2"); 69939325b59STrilok Soni MODULE_DESCRIPTION("PMIC8XXX keypad driver"); 70039325b59STrilok Soni MODULE_VERSION("1.0"); 70139325b59STrilok Soni MODULE_ALIAS("platform:pmic8xxx_keypad"); 70239325b59STrilok Soni MODULE_AUTHOR("Trilok Soni <tsoni@codeaurora.org>"); 703