197fb5e8dSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 239325b59STrilok Soni /* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved. 339325b59STrilok Soni */ 439325b59STrilok Soni 539325b59STrilok Soni #include <linux/module.h> 639325b59STrilok Soni #include <linux/platform_device.h> 739325b59STrilok Soni #include <linux/kernel.h> 839325b59STrilok Soni #include <linux/interrupt.h> 939325b59STrilok Soni #include <linux/slab.h> 1039325b59STrilok Soni #include <linux/input.h> 1139325b59STrilok Soni #include <linux/bitops.h> 1239325b59STrilok Soni #include <linux/delay.h> 1339325b59STrilok Soni #include <linux/mutex.h> 14a5dde0c7SStephen Boyd #include <linux/regmap.h> 1586ea5e6bSStephen Boyd #include <linux/of.h> 1686ea5e6bSStephen Boyd #include <linux/input/matrix_keypad.h> 1739325b59STrilok Soni 1839325b59STrilok Soni #define PM8XXX_MAX_ROWS 18 1939325b59STrilok Soni #define PM8XXX_MAX_COLS 8 2039325b59STrilok Soni #define PM8XXX_ROW_SHIFT 3 2139325b59STrilok Soni #define PM8XXX_MATRIX_MAX_SIZE (PM8XXX_MAX_ROWS * PM8XXX_MAX_COLS) 2239325b59STrilok Soni 2339325b59STrilok Soni #define PM8XXX_MIN_ROWS 5 2439325b59STrilok Soni #define PM8XXX_MIN_COLS 5 2539325b59STrilok Soni 2639325b59STrilok Soni #define MAX_SCAN_DELAY 128 2739325b59STrilok Soni #define MIN_SCAN_DELAY 1 2839325b59STrilok Soni 2939325b59STrilok Soni /* in nanoseconds */ 3039325b59STrilok Soni #define MAX_ROW_HOLD_DELAY 122000 3139325b59STrilok Soni #define MIN_ROW_HOLD_DELAY 30500 3239325b59STrilok Soni 3339325b59STrilok Soni #define MAX_DEBOUNCE_TIME 20 3439325b59STrilok Soni #define MIN_DEBOUNCE_TIME 5 3539325b59STrilok Soni 3639325b59STrilok Soni #define KEYP_CTRL 0x148 3739325b59STrilok Soni 3839325b59STrilok Soni #define KEYP_CTRL_EVNTS BIT(0) 3939325b59STrilok Soni #define KEYP_CTRL_EVNTS_MASK 0x3 4039325b59STrilok Soni 4139325b59STrilok Soni #define KEYP_CTRL_SCAN_COLS_SHIFT 5 4239325b59STrilok Soni #define KEYP_CTRL_SCAN_COLS_MIN 5 4339325b59STrilok Soni #define KEYP_CTRL_SCAN_COLS_BITS 0x3 4439325b59STrilok Soni 4539325b59STrilok Soni #define KEYP_CTRL_SCAN_ROWS_SHIFT 2 4639325b59STrilok Soni #define KEYP_CTRL_SCAN_ROWS_MIN 5 4739325b59STrilok Soni #define KEYP_CTRL_SCAN_ROWS_BITS 0x7 4839325b59STrilok Soni 4939325b59STrilok Soni #define KEYP_CTRL_KEYP_EN BIT(7) 5039325b59STrilok Soni 5139325b59STrilok Soni #define KEYP_SCAN 0x149 5239325b59STrilok Soni 5339325b59STrilok Soni #define KEYP_SCAN_READ_STATE BIT(0) 5439325b59STrilok Soni #define KEYP_SCAN_DBOUNCE_SHIFT 1 5539325b59STrilok Soni #define KEYP_SCAN_PAUSE_SHIFT 3 5639325b59STrilok Soni #define KEYP_SCAN_ROW_HOLD_SHIFT 6 5739325b59STrilok Soni 5839325b59STrilok Soni #define KEYP_TEST 0x14A 5939325b59STrilok Soni 6039325b59STrilok Soni #define KEYP_TEST_CLEAR_RECENT_SCAN BIT(6) 6139325b59STrilok Soni #define KEYP_TEST_CLEAR_OLD_SCAN BIT(5) 6239325b59STrilok Soni #define KEYP_TEST_READ_RESET BIT(4) 6339325b59STrilok Soni #define KEYP_TEST_DTEST_EN BIT(3) 6439325b59STrilok Soni #define KEYP_TEST_ABORT_READ BIT(0) 6539325b59STrilok Soni 6639325b59STrilok Soni #define KEYP_TEST_DBG_SELECT_SHIFT 1 6739325b59STrilok Soni 6839325b59STrilok Soni /* bits of these registers represent 6939325b59STrilok Soni * '0' for key press 7039325b59STrilok Soni * '1' for key release 7139325b59STrilok Soni */ 7239325b59STrilok Soni #define KEYP_RECENT_DATA 0x14B 7339325b59STrilok Soni #define KEYP_OLD_DATA 0x14C 7439325b59STrilok Soni 7539325b59STrilok Soni #define KEYP_CLOCK_FREQ 32768 7639325b59STrilok Soni 7739325b59STrilok Soni /** 7839325b59STrilok Soni * struct pmic8xxx_kp - internal keypad data structure 7955be5087SLee Jones * @num_cols: number of columns of keypad 8055be5087SLee Jones * @num_rows: number of row of keypad 8155be5087SLee Jones * @input: input device pointer for keypad 8255be5087SLee Jones * @regmap: regmap handle 8355be5087SLee Jones * @key_sense_irq: key press/release irq number 8455be5087SLee Jones * @key_stuck_irq: key stuck notification irq number 8555be5087SLee Jones * @keycodes: array to hold the key codes 8655be5087SLee Jones * @dev: parent device pointer 8755be5087SLee Jones * @keystate: present key press/release state 8855be5087SLee Jones * @stuckstate: present state when key stuck irq 8955be5087SLee Jones * @ctrl_reg: control register value 9039325b59STrilok Soni */ 9139325b59STrilok Soni struct pmic8xxx_kp { 9286ea5e6bSStephen Boyd unsigned int num_rows; 9386ea5e6bSStephen Boyd unsigned int num_cols; 9439325b59STrilok Soni struct input_dev *input; 95a5dde0c7SStephen Boyd struct regmap *regmap; 9639325b59STrilok Soni int key_sense_irq; 9739325b59STrilok Soni int key_stuck_irq; 9839325b59STrilok Soni 9939325b59STrilok Soni unsigned short keycodes[PM8XXX_MATRIX_MAX_SIZE]; 10039325b59STrilok Soni 10139325b59STrilok Soni struct device *dev; 10239325b59STrilok Soni u16 keystate[PM8XXX_MAX_ROWS]; 10339325b59STrilok Soni u16 stuckstate[PM8XXX_MAX_ROWS]; 10439325b59STrilok Soni 10539325b59STrilok Soni u8 ctrl_reg; 10639325b59STrilok Soni }; 10739325b59STrilok Soni 10839325b59STrilok Soni static u8 pmic8xxx_col_state(struct pmic8xxx_kp *kp, u8 col) 10939325b59STrilok Soni { 11039325b59STrilok Soni /* all keys pressed on that particular row? */ 11139325b59STrilok Soni if (col == 0x00) 11286ea5e6bSStephen Boyd return 1 << kp->num_cols; 11339325b59STrilok Soni else 11486ea5e6bSStephen Boyd return col & ((1 << kp->num_cols) - 1); 11539325b59STrilok Soni } 11639325b59STrilok Soni 11739325b59STrilok Soni /* 11839325b59STrilok Soni * Synchronous read protocol for RevB0 onwards: 11939325b59STrilok Soni * 12039325b59STrilok Soni * 1. Write '1' to ReadState bit in KEYP_SCAN register 12139325b59STrilok Soni * 2. Wait 2*32KHz clocks, so that HW can successfully enter read mode 12239325b59STrilok Soni * synchronously 12339325b59STrilok Soni * 3. Read rows in old array first if events are more than one 12439325b59STrilok Soni * 4. Read rows in recent array 12539325b59STrilok Soni * 5. Wait 4*32KHz clocks 12639325b59STrilok Soni * 6. Write '0' to ReadState bit of KEYP_SCAN register so that hw can 12739325b59STrilok Soni * synchronously exit read mode. 12839325b59STrilok Soni */ 12939325b59STrilok Soni static int pmic8xxx_chk_sync_read(struct pmic8xxx_kp *kp) 13039325b59STrilok Soni { 13139325b59STrilok Soni int rc; 132a5dde0c7SStephen Boyd unsigned int scan_val; 13339325b59STrilok Soni 134a5dde0c7SStephen Boyd rc = regmap_read(kp->regmap, KEYP_SCAN, &scan_val); 13539325b59STrilok Soni if (rc < 0) { 13639325b59STrilok Soni dev_err(kp->dev, "Error reading KEYP_SCAN reg, rc=%d\n", rc); 13739325b59STrilok Soni return rc; 13839325b59STrilok Soni } 13939325b59STrilok Soni 14039325b59STrilok Soni scan_val |= 0x1; 14139325b59STrilok Soni 142a5dde0c7SStephen Boyd rc = regmap_write(kp->regmap, KEYP_SCAN, scan_val); 14339325b59STrilok Soni if (rc < 0) { 14439325b59STrilok Soni dev_err(kp->dev, "Error writing KEYP_SCAN reg, rc=%d\n", rc); 14539325b59STrilok Soni return rc; 14639325b59STrilok Soni } 14739325b59STrilok Soni 14839325b59STrilok Soni /* 2 * 32KHz clocks */ 14939325b59STrilok Soni udelay((2 * DIV_ROUND_UP(USEC_PER_SEC, KEYP_CLOCK_FREQ)) + 1); 15039325b59STrilok Soni 15139325b59STrilok Soni return rc; 15239325b59STrilok Soni } 15339325b59STrilok Soni 15439325b59STrilok Soni static int pmic8xxx_kp_read_data(struct pmic8xxx_kp *kp, u16 *state, 15539325b59STrilok Soni u16 data_reg, int read_rows) 15639325b59STrilok Soni { 15739325b59STrilok Soni int rc, row; 158a5dde0c7SStephen Boyd unsigned int val; 15939325b59STrilok Soni 160a5dde0c7SStephen Boyd for (row = 0; row < read_rows; row++) { 161a5dde0c7SStephen Boyd rc = regmap_read(kp->regmap, data_reg, &val); 16239325b59STrilok Soni if (rc) 16339325b59STrilok Soni return rc; 164a5dde0c7SStephen Boyd dev_dbg(kp->dev, "%d = %d\n", row, val); 165a5dde0c7SStephen Boyd state[row] = pmic8xxx_col_state(kp, val); 16639325b59STrilok Soni } 16739325b59STrilok Soni 168a5dde0c7SStephen Boyd return 0; 16939325b59STrilok Soni } 17039325b59STrilok Soni 17139325b59STrilok Soni static int pmic8xxx_kp_read_matrix(struct pmic8xxx_kp *kp, u16 *new_state, 17239325b59STrilok Soni u16 *old_state) 17339325b59STrilok Soni { 17439325b59STrilok Soni int rc, read_rows; 175a5dde0c7SStephen Boyd unsigned int scan_val; 17639325b59STrilok Soni 17786ea5e6bSStephen Boyd if (kp->num_rows < PM8XXX_MIN_ROWS) 17839325b59STrilok Soni read_rows = PM8XXX_MIN_ROWS; 17939325b59STrilok Soni else 18086ea5e6bSStephen Boyd read_rows = kp->num_rows; 18139325b59STrilok Soni 18239325b59STrilok Soni pmic8xxx_chk_sync_read(kp); 18339325b59STrilok Soni 18439325b59STrilok Soni if (old_state) { 18539325b59STrilok Soni rc = pmic8xxx_kp_read_data(kp, old_state, KEYP_OLD_DATA, 18639325b59STrilok Soni read_rows); 18739325b59STrilok Soni if (rc < 0) { 18839325b59STrilok Soni dev_err(kp->dev, 18939325b59STrilok Soni "Error reading KEYP_OLD_DATA, rc=%d\n", rc); 19039325b59STrilok Soni return rc; 19139325b59STrilok Soni } 19239325b59STrilok Soni } 19339325b59STrilok Soni 19439325b59STrilok Soni rc = pmic8xxx_kp_read_data(kp, new_state, KEYP_RECENT_DATA, 19539325b59STrilok Soni read_rows); 19639325b59STrilok Soni if (rc < 0) { 19739325b59STrilok Soni dev_err(kp->dev, 19839325b59STrilok Soni "Error reading KEYP_RECENT_DATA, rc=%d\n", rc); 19939325b59STrilok Soni return rc; 20039325b59STrilok Soni } 20139325b59STrilok Soni 20239325b59STrilok Soni /* 4 * 32KHz clocks */ 20339325b59STrilok Soni udelay((4 * DIV_ROUND_UP(USEC_PER_SEC, KEYP_CLOCK_FREQ)) + 1); 20439325b59STrilok Soni 205a5dde0c7SStephen Boyd rc = regmap_read(kp->regmap, KEYP_SCAN, &scan_val); 20639325b59STrilok Soni if (rc < 0) { 20739325b59STrilok Soni dev_err(kp->dev, "Error reading KEYP_SCAN reg, rc=%d\n", rc); 20839325b59STrilok Soni return rc; 20939325b59STrilok Soni } 21039325b59STrilok Soni 21139325b59STrilok Soni scan_val &= 0xFE; 212a5dde0c7SStephen Boyd rc = regmap_write(kp->regmap, KEYP_SCAN, scan_val); 21339325b59STrilok Soni if (rc < 0) 21439325b59STrilok Soni dev_err(kp->dev, "Error writing KEYP_SCAN reg, rc=%d\n", rc); 21539325b59STrilok Soni 21639325b59STrilok Soni return rc; 21739325b59STrilok Soni } 21839325b59STrilok Soni 21939325b59STrilok Soni static void __pmic8xxx_kp_scan_matrix(struct pmic8xxx_kp *kp, u16 *new_state, 22039325b59STrilok Soni u16 *old_state) 22139325b59STrilok Soni { 22239325b59STrilok Soni int row, col, code; 22339325b59STrilok Soni 22486ea5e6bSStephen Boyd for (row = 0; row < kp->num_rows; row++) { 22539325b59STrilok Soni int bits_changed = new_state[row] ^ old_state[row]; 22639325b59STrilok Soni 22739325b59STrilok Soni if (!bits_changed) 22839325b59STrilok Soni continue; 22939325b59STrilok Soni 23086ea5e6bSStephen Boyd for (col = 0; col < kp->num_cols; col++) { 23139325b59STrilok Soni if (!(bits_changed & (1 << col))) 23239325b59STrilok Soni continue; 23339325b59STrilok Soni 23439325b59STrilok Soni dev_dbg(kp->dev, "key [%d:%d] %s\n", row, col, 23539325b59STrilok Soni !(new_state[row] & (1 << col)) ? 23639325b59STrilok Soni "pressed" : "released"); 23739325b59STrilok Soni 23839325b59STrilok Soni code = MATRIX_SCAN_CODE(row, col, PM8XXX_ROW_SHIFT); 23939325b59STrilok Soni 24039325b59STrilok Soni input_event(kp->input, EV_MSC, MSC_SCAN, code); 24139325b59STrilok Soni input_report_key(kp->input, 24239325b59STrilok Soni kp->keycodes[code], 24339325b59STrilok Soni !(new_state[row] & (1 << col))); 24439325b59STrilok Soni 24539325b59STrilok Soni input_sync(kp->input); 24639325b59STrilok Soni } 24739325b59STrilok Soni } 24839325b59STrilok Soni } 24939325b59STrilok Soni 25039325b59STrilok Soni static bool pmic8xxx_detect_ghost_keys(struct pmic8xxx_kp *kp, u16 *new_state) 25139325b59STrilok Soni { 25239325b59STrilok Soni int row, found_first = -1; 25339325b59STrilok Soni u16 check, row_state; 25439325b59STrilok Soni 25539325b59STrilok Soni check = 0; 25686ea5e6bSStephen Boyd for (row = 0; row < kp->num_rows; row++) { 25739325b59STrilok Soni row_state = (~new_state[row]) & 25886ea5e6bSStephen Boyd ((1 << kp->num_cols) - 1); 25939325b59STrilok Soni 26039325b59STrilok Soni if (hweight16(row_state) > 1) { 26139325b59STrilok Soni if (found_first == -1) 26239325b59STrilok Soni found_first = row; 26339325b59STrilok Soni if (check & row_state) { 26439325b59STrilok Soni dev_dbg(kp->dev, "detected ghost key on row[%d]" 26539325b59STrilok Soni " and row[%d]\n", found_first, row); 26639325b59STrilok Soni return true; 26739325b59STrilok Soni } 26839325b59STrilok Soni } 26939325b59STrilok Soni check |= row_state; 27039325b59STrilok Soni } 27139325b59STrilok Soni return false; 27239325b59STrilok Soni } 27339325b59STrilok Soni 27439325b59STrilok Soni static int pmic8xxx_kp_scan_matrix(struct pmic8xxx_kp *kp, unsigned int events) 27539325b59STrilok Soni { 27639325b59STrilok Soni u16 new_state[PM8XXX_MAX_ROWS]; 27739325b59STrilok Soni u16 old_state[PM8XXX_MAX_ROWS]; 27839325b59STrilok Soni int rc; 27939325b59STrilok Soni 28039325b59STrilok Soni switch (events) { 28139325b59STrilok Soni case 0x1: 28239325b59STrilok Soni rc = pmic8xxx_kp_read_matrix(kp, new_state, NULL); 28339325b59STrilok Soni if (rc < 0) 28439325b59STrilok Soni return rc; 28539325b59STrilok Soni 28639325b59STrilok Soni /* detecting ghost key is not an error */ 28739325b59STrilok Soni if (pmic8xxx_detect_ghost_keys(kp, new_state)) 28839325b59STrilok Soni return 0; 28939325b59STrilok Soni __pmic8xxx_kp_scan_matrix(kp, new_state, kp->keystate); 29039325b59STrilok Soni memcpy(kp->keystate, new_state, sizeof(new_state)); 29139325b59STrilok Soni break; 29239325b59STrilok Soni case 0x3: /* two events - eventcounter is gray-coded */ 29339325b59STrilok Soni rc = pmic8xxx_kp_read_matrix(kp, new_state, old_state); 29439325b59STrilok Soni if (rc < 0) 29539325b59STrilok Soni return rc; 29639325b59STrilok Soni 29739325b59STrilok Soni __pmic8xxx_kp_scan_matrix(kp, old_state, kp->keystate); 29839325b59STrilok Soni __pmic8xxx_kp_scan_matrix(kp, new_state, old_state); 29939325b59STrilok Soni memcpy(kp->keystate, new_state, sizeof(new_state)); 30039325b59STrilok Soni break; 30139325b59STrilok Soni case 0x2: 30239325b59STrilok Soni dev_dbg(kp->dev, "Some key events were lost\n"); 30339325b59STrilok Soni rc = pmic8xxx_kp_read_matrix(kp, new_state, old_state); 30439325b59STrilok Soni if (rc < 0) 30539325b59STrilok Soni return rc; 30639325b59STrilok Soni __pmic8xxx_kp_scan_matrix(kp, old_state, kp->keystate); 30739325b59STrilok Soni __pmic8xxx_kp_scan_matrix(kp, new_state, old_state); 30839325b59STrilok Soni memcpy(kp->keystate, new_state, sizeof(new_state)); 30939325b59STrilok Soni break; 31039325b59STrilok Soni default: 31139325b59STrilok Soni rc = -EINVAL; 31239325b59STrilok Soni } 31339325b59STrilok Soni return rc; 31439325b59STrilok Soni } 31539325b59STrilok Soni 31639325b59STrilok Soni /* 31739325b59STrilok Soni * NOTE: We are reading recent and old data registers blindly 31839325b59STrilok Soni * whenever key-stuck interrupt happens, because events counter doesn't 31939325b59STrilok Soni * get updated when this interrupt happens due to key stuck doesn't get 32039325b59STrilok Soni * considered as key state change. 32139325b59STrilok Soni * 32239325b59STrilok Soni * We are not using old data register contents after they are being read 32339325b59STrilok Soni * because it might report the key which was pressed before the key being stuck 32439325b59STrilok Soni * as stuck key because it's pressed status is stored in the old data 32539325b59STrilok Soni * register. 32639325b59STrilok Soni */ 32739325b59STrilok Soni static irqreturn_t pmic8xxx_kp_stuck_irq(int irq, void *data) 32839325b59STrilok Soni { 32939325b59STrilok Soni u16 new_state[PM8XXX_MAX_ROWS]; 33039325b59STrilok Soni u16 old_state[PM8XXX_MAX_ROWS]; 33139325b59STrilok Soni int rc; 33239325b59STrilok Soni struct pmic8xxx_kp *kp = data; 33339325b59STrilok Soni 33439325b59STrilok Soni rc = pmic8xxx_kp_read_matrix(kp, new_state, old_state); 33539325b59STrilok Soni if (rc < 0) { 33639325b59STrilok Soni dev_err(kp->dev, "failed to read keypad matrix\n"); 33739325b59STrilok Soni return IRQ_HANDLED; 33839325b59STrilok Soni } 33939325b59STrilok Soni 34039325b59STrilok Soni __pmic8xxx_kp_scan_matrix(kp, new_state, kp->stuckstate); 34139325b59STrilok Soni 34239325b59STrilok Soni return IRQ_HANDLED; 34339325b59STrilok Soni } 34439325b59STrilok Soni 34539325b59STrilok Soni static irqreturn_t pmic8xxx_kp_irq(int irq, void *data) 34639325b59STrilok Soni { 34739325b59STrilok Soni struct pmic8xxx_kp *kp = data; 348a5dde0c7SStephen Boyd unsigned int ctrl_val, events; 34939325b59STrilok Soni int rc; 35039325b59STrilok Soni 351a5dde0c7SStephen Boyd rc = regmap_read(kp->regmap, KEYP_CTRL, &ctrl_val); 35239325b59STrilok Soni if (rc < 0) { 35339325b59STrilok Soni dev_err(kp->dev, "failed to read keyp_ctrl register\n"); 35439325b59STrilok Soni return IRQ_HANDLED; 35539325b59STrilok Soni } 35639325b59STrilok Soni 35739325b59STrilok Soni events = ctrl_val & KEYP_CTRL_EVNTS_MASK; 35839325b59STrilok Soni 35939325b59STrilok Soni rc = pmic8xxx_kp_scan_matrix(kp, events); 36039325b59STrilok Soni if (rc < 0) 36139325b59STrilok Soni dev_err(kp->dev, "failed to scan matrix\n"); 36239325b59STrilok Soni 36339325b59STrilok Soni return IRQ_HANDLED; 36439325b59STrilok Soni } 36539325b59STrilok Soni 36686ea5e6bSStephen Boyd static int pmic8xxx_kpd_init(struct pmic8xxx_kp *kp, 36786ea5e6bSStephen Boyd struct platform_device *pdev) 36839325b59STrilok Soni { 36986ea5e6bSStephen Boyd const struct device_node *of_node = pdev->dev.of_node; 37086ea5e6bSStephen Boyd unsigned int scan_delay_ms; 37186ea5e6bSStephen Boyd unsigned int row_hold_ns; 37286ea5e6bSStephen Boyd unsigned int debounce_ms; 37339325b59STrilok Soni int bits, rc, cycles; 37439325b59STrilok Soni u8 scan_val = 0, ctrl_val = 0; 37539325b59STrilok Soni static const u8 row_bits[] = { 37639325b59STrilok Soni 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 7, 7, 7, 37739325b59STrilok Soni }; 37839325b59STrilok Soni 37939325b59STrilok Soni /* Find column bits */ 38086ea5e6bSStephen Boyd if (kp->num_cols < KEYP_CTRL_SCAN_COLS_MIN) 38139325b59STrilok Soni bits = 0; 38239325b59STrilok Soni else 38386ea5e6bSStephen Boyd bits = kp->num_cols - KEYP_CTRL_SCAN_COLS_MIN; 38439325b59STrilok Soni ctrl_val = (bits & KEYP_CTRL_SCAN_COLS_BITS) << 38539325b59STrilok Soni KEYP_CTRL_SCAN_COLS_SHIFT; 38639325b59STrilok Soni 38739325b59STrilok Soni /* Find row bits */ 38886ea5e6bSStephen Boyd if (kp->num_rows < KEYP_CTRL_SCAN_ROWS_MIN) 38939325b59STrilok Soni bits = 0; 39039325b59STrilok Soni else 39186ea5e6bSStephen Boyd bits = row_bits[kp->num_rows - KEYP_CTRL_SCAN_ROWS_MIN]; 39239325b59STrilok Soni 39339325b59STrilok Soni ctrl_val |= (bits << KEYP_CTRL_SCAN_ROWS_SHIFT); 39439325b59STrilok Soni 395a5dde0c7SStephen Boyd rc = regmap_write(kp->regmap, KEYP_CTRL, ctrl_val); 39639325b59STrilok Soni if (rc < 0) { 39739325b59STrilok Soni dev_err(kp->dev, "Error writing KEYP_CTRL reg, rc=%d\n", rc); 39839325b59STrilok Soni return rc; 39939325b59STrilok Soni } 40039325b59STrilok Soni 40186ea5e6bSStephen Boyd if (of_property_read_u32(of_node, "scan-delay", &scan_delay_ms)) 40286ea5e6bSStephen Boyd scan_delay_ms = MIN_SCAN_DELAY; 40386ea5e6bSStephen Boyd 40486ea5e6bSStephen Boyd if (scan_delay_ms > MAX_SCAN_DELAY || scan_delay_ms < MIN_SCAN_DELAY || 40586ea5e6bSStephen Boyd !is_power_of_2(scan_delay_ms)) { 40686ea5e6bSStephen Boyd dev_err(&pdev->dev, "invalid keypad scan time supplied\n"); 40786ea5e6bSStephen Boyd return -EINVAL; 40886ea5e6bSStephen Boyd } 40986ea5e6bSStephen Boyd 41086ea5e6bSStephen Boyd if (of_property_read_u32(of_node, "row-hold", &row_hold_ns)) 41186ea5e6bSStephen Boyd row_hold_ns = MIN_ROW_HOLD_DELAY; 41286ea5e6bSStephen Boyd 41386ea5e6bSStephen Boyd if (row_hold_ns > MAX_ROW_HOLD_DELAY || 41486ea5e6bSStephen Boyd row_hold_ns < MIN_ROW_HOLD_DELAY || 41586ea5e6bSStephen Boyd ((row_hold_ns % MIN_ROW_HOLD_DELAY) != 0)) { 41686ea5e6bSStephen Boyd dev_err(&pdev->dev, "invalid keypad row hold time supplied\n"); 41786ea5e6bSStephen Boyd return -EINVAL; 41886ea5e6bSStephen Boyd } 41986ea5e6bSStephen Boyd 42086ea5e6bSStephen Boyd if (of_property_read_u32(of_node, "debounce", &debounce_ms)) 42186ea5e6bSStephen Boyd debounce_ms = MIN_DEBOUNCE_TIME; 42286ea5e6bSStephen Boyd 42386ea5e6bSStephen Boyd if (((debounce_ms % 5) != 0) || 42486ea5e6bSStephen Boyd debounce_ms > MAX_DEBOUNCE_TIME || 42586ea5e6bSStephen Boyd debounce_ms < MIN_DEBOUNCE_TIME) { 42686ea5e6bSStephen Boyd dev_err(&pdev->dev, "invalid debounce time supplied\n"); 42786ea5e6bSStephen Boyd return -EINVAL; 42886ea5e6bSStephen Boyd } 42986ea5e6bSStephen Boyd 43086ea5e6bSStephen Boyd bits = (debounce_ms / 5) - 1; 43139325b59STrilok Soni 43239325b59STrilok Soni scan_val |= (bits << KEYP_SCAN_DBOUNCE_SHIFT); 43339325b59STrilok Soni 43486ea5e6bSStephen Boyd bits = fls(scan_delay_ms) - 1; 43539325b59STrilok Soni scan_val |= (bits << KEYP_SCAN_PAUSE_SHIFT); 43639325b59STrilok Soni 43739325b59STrilok Soni /* Row hold time is a multiple of 32KHz cycles. */ 43886ea5e6bSStephen Boyd cycles = (row_hold_ns * KEYP_CLOCK_FREQ) / NSEC_PER_SEC; 43939325b59STrilok Soni 44039325b59STrilok Soni scan_val |= (cycles << KEYP_SCAN_ROW_HOLD_SHIFT); 44139325b59STrilok Soni 442a5dde0c7SStephen Boyd rc = regmap_write(kp->regmap, KEYP_SCAN, scan_val); 44339325b59STrilok Soni if (rc) 44439325b59STrilok Soni dev_err(kp->dev, "Error writing KEYP_SCAN reg, rc=%d\n", rc); 44539325b59STrilok Soni 44639325b59STrilok Soni return rc; 44739325b59STrilok Soni 44839325b59STrilok Soni } 44939325b59STrilok Soni 45039325b59STrilok Soni static int pmic8xxx_kp_enable(struct pmic8xxx_kp *kp) 45139325b59STrilok Soni { 45239325b59STrilok Soni int rc; 45339325b59STrilok Soni 45439325b59STrilok Soni kp->ctrl_reg |= KEYP_CTRL_KEYP_EN; 45539325b59STrilok Soni 456a5dde0c7SStephen Boyd rc = regmap_write(kp->regmap, KEYP_CTRL, kp->ctrl_reg); 45739325b59STrilok Soni if (rc < 0) 45839325b59STrilok Soni dev_err(kp->dev, "Error writing KEYP_CTRL reg, rc=%d\n", rc); 45939325b59STrilok Soni 46039325b59STrilok Soni return rc; 46139325b59STrilok Soni } 46239325b59STrilok Soni 46339325b59STrilok Soni static int pmic8xxx_kp_disable(struct pmic8xxx_kp *kp) 46439325b59STrilok Soni { 46539325b59STrilok Soni int rc; 46639325b59STrilok Soni 46739325b59STrilok Soni kp->ctrl_reg &= ~KEYP_CTRL_KEYP_EN; 46839325b59STrilok Soni 469a5dde0c7SStephen Boyd rc = regmap_write(kp->regmap, KEYP_CTRL, kp->ctrl_reg); 47039325b59STrilok Soni if (rc < 0) 47139325b59STrilok Soni return rc; 47239325b59STrilok Soni 47339325b59STrilok Soni return rc; 47439325b59STrilok Soni } 47539325b59STrilok Soni 47639325b59STrilok Soni static int pmic8xxx_kp_open(struct input_dev *dev) 47739325b59STrilok Soni { 47839325b59STrilok Soni struct pmic8xxx_kp *kp = input_get_drvdata(dev); 47939325b59STrilok Soni 48039325b59STrilok Soni return pmic8xxx_kp_enable(kp); 48139325b59STrilok Soni } 48239325b59STrilok Soni 48339325b59STrilok Soni static void pmic8xxx_kp_close(struct input_dev *dev) 48439325b59STrilok Soni { 48539325b59STrilok Soni struct pmic8xxx_kp *kp = input_get_drvdata(dev); 48639325b59STrilok Soni 48739325b59STrilok Soni pmic8xxx_kp_disable(kp); 48839325b59STrilok Soni } 48939325b59STrilok Soni 49039325b59STrilok Soni /* 49139325b59STrilok Soni * keypad controller should be initialized in the following sequence 49239325b59STrilok Soni * only, otherwise it might get into FSM stuck state. 49339325b59STrilok Soni * 49439325b59STrilok Soni * - Initialize keypad control parameters, like no. of rows, columns, 49539325b59STrilok Soni * timing values etc., 49639325b59STrilok Soni * - configure rows and column gpios pull up/down. 49739325b59STrilok Soni * - set irq edge type. 49839325b59STrilok Soni * - enable the keypad controller. 49939325b59STrilok Soni */ 5005298cc4cSBill Pemberton static int pmic8xxx_kp_probe(struct platform_device *pdev) 50139325b59STrilok Soni { 50227469652SDmitry Torokhov struct device_node *np = pdev->dev.of_node; 50386ea5e6bSStephen Boyd unsigned int rows, cols; 50486ea5e6bSStephen Boyd bool repeat; 50586ea5e6bSStephen Boyd bool wakeup; 50639325b59STrilok Soni struct pmic8xxx_kp *kp; 50739325b59STrilok Soni int rc; 508a5dde0c7SStephen Boyd unsigned int ctrl_val; 50939325b59STrilok Soni 510aef01aadSDmitry Torokhov rc = matrix_keypad_parse_properties(&pdev->dev, &rows, &cols); 51186ea5e6bSStephen Boyd if (rc) 51286ea5e6bSStephen Boyd return rc; 51386ea5e6bSStephen Boyd 51486ea5e6bSStephen Boyd if (cols > PM8XXX_MAX_COLS || rows > PM8XXX_MAX_ROWS || 51586ea5e6bSStephen Boyd cols < PM8XXX_MIN_COLS) { 51639325b59STrilok Soni dev_err(&pdev->dev, "invalid platform data\n"); 51739325b59STrilok Soni return -EINVAL; 51839325b59STrilok Soni } 51939325b59STrilok Soni 52027469652SDmitry Torokhov repeat = !of_property_read_bool(np, "linux,input-no-autorepeat"); 52127469652SDmitry Torokhov 52227469652SDmitry Torokhov wakeup = of_property_read_bool(np, "wakeup-source") || 52327469652SDmitry Torokhov /* legacy name */ 52427469652SDmitry Torokhov of_property_read_bool(np, "linux,keypad-wakeup"); 52539325b59STrilok Soni 526c7f6ee26SStephen Boyd kp = devm_kzalloc(&pdev->dev, sizeof(*kp), GFP_KERNEL); 52739325b59STrilok Soni if (!kp) 52839325b59STrilok Soni return -ENOMEM; 52939325b59STrilok Soni 530a5dde0c7SStephen Boyd kp->regmap = dev_get_regmap(pdev->dev.parent, NULL); 531a5dde0c7SStephen Boyd if (!kp->regmap) 532a5dde0c7SStephen Boyd return -ENODEV; 533a5dde0c7SStephen Boyd 53439325b59STrilok Soni platform_set_drvdata(pdev, kp); 53539325b59STrilok Soni 53686ea5e6bSStephen Boyd kp->num_rows = rows; 53786ea5e6bSStephen Boyd kp->num_cols = cols; 53839325b59STrilok Soni kp->dev = &pdev->dev; 53939325b59STrilok Soni 540c7f6ee26SStephen Boyd kp->input = devm_input_allocate_device(&pdev->dev); 54139325b59STrilok Soni if (!kp->input) { 54239325b59STrilok Soni dev_err(&pdev->dev, "unable to allocate input device\n"); 543c7f6ee26SStephen Boyd return -ENOMEM; 54439325b59STrilok Soni } 54539325b59STrilok Soni 54639325b59STrilok Soni kp->key_sense_irq = platform_get_irq(pdev, 0); 5470bec8b7eSStephen Boyd if (kp->key_sense_irq < 0) 548c7f6ee26SStephen Boyd return kp->key_sense_irq; 54939325b59STrilok Soni 55039325b59STrilok Soni kp->key_stuck_irq = platform_get_irq(pdev, 1); 5510bec8b7eSStephen Boyd if (kp->key_stuck_irq < 0) 552c7f6ee26SStephen Boyd return kp->key_stuck_irq; 55339325b59STrilok Soni 55486ea5e6bSStephen Boyd kp->input->name = "PMIC8XXX keypad"; 55586ea5e6bSStephen Boyd kp->input->phys = "pmic8xxx_keypad/input0"; 55639325b59STrilok Soni 55739325b59STrilok Soni kp->input->id.bustype = BUS_I2C; 55839325b59STrilok Soni kp->input->id.version = 0x0001; 55939325b59STrilok Soni kp->input->id.product = 0x0001; 56039325b59STrilok Soni kp->input->id.vendor = 0x0001; 56139325b59STrilok Soni 56239325b59STrilok Soni kp->input->open = pmic8xxx_kp_open; 56339325b59STrilok Soni kp->input->close = pmic8xxx_kp_close; 56439325b59STrilok Soni 56586ea5e6bSStephen Boyd rc = matrix_keypad_build_keymap(NULL, NULL, 5661932811fSDmitry Torokhov PM8XXX_MAX_ROWS, PM8XXX_MAX_COLS, 5671932811fSDmitry Torokhov kp->keycodes, kp->input); 5681932811fSDmitry Torokhov if (rc) { 5691932811fSDmitry Torokhov dev_err(&pdev->dev, "failed to build keymap\n"); 570c7f6ee26SStephen Boyd return rc; 5711932811fSDmitry Torokhov } 57239325b59STrilok Soni 57386ea5e6bSStephen Boyd if (repeat) 5741932811fSDmitry Torokhov __set_bit(EV_REP, kp->input->evbit); 57539325b59STrilok Soni input_set_capability(kp->input, EV_MSC, MSC_SCAN); 5761932811fSDmitry Torokhov 57739325b59STrilok Soni input_set_drvdata(kp->input, kp); 57839325b59STrilok Soni 57939325b59STrilok Soni /* initialize keypad state */ 58039325b59STrilok Soni memset(kp->keystate, 0xff, sizeof(kp->keystate)); 58139325b59STrilok Soni memset(kp->stuckstate, 0xff, sizeof(kp->stuckstate)); 58239325b59STrilok Soni 58386ea5e6bSStephen Boyd rc = pmic8xxx_kpd_init(kp, pdev); 58439325b59STrilok Soni if (rc < 0) { 58539325b59STrilok Soni dev_err(&pdev->dev, "unable to initialize keypad controller\n"); 586c7f6ee26SStephen Boyd return rc; 58739325b59STrilok Soni } 58839325b59STrilok Soni 589c7f6ee26SStephen Boyd rc = devm_request_any_context_irq(&pdev->dev, kp->key_sense_irq, 590c7f6ee26SStephen Boyd pmic8xxx_kp_irq, IRQF_TRIGGER_RISING, "pmic-keypad", 591c7f6ee26SStephen Boyd kp); 59239325b59STrilok Soni if (rc < 0) { 59339325b59STrilok Soni dev_err(&pdev->dev, "failed to request keypad sense irq\n"); 594c7f6ee26SStephen Boyd return rc; 59539325b59STrilok Soni } 59639325b59STrilok Soni 597c7f6ee26SStephen Boyd rc = devm_request_any_context_irq(&pdev->dev, kp->key_stuck_irq, 598c7f6ee26SStephen Boyd pmic8xxx_kp_stuck_irq, IRQF_TRIGGER_RISING, 599c7f6ee26SStephen Boyd "pmic-keypad-stuck", kp); 60039325b59STrilok Soni if (rc < 0) { 60139325b59STrilok Soni dev_err(&pdev->dev, "failed to request keypad stuck irq\n"); 602c7f6ee26SStephen Boyd return rc; 60339325b59STrilok Soni } 60439325b59STrilok Soni 605a5dde0c7SStephen Boyd rc = regmap_read(kp->regmap, KEYP_CTRL, &ctrl_val); 60639325b59STrilok Soni if (rc < 0) { 60739325b59STrilok Soni dev_err(&pdev->dev, "failed to read KEYP_CTRL register\n"); 608c7f6ee26SStephen Boyd return rc; 60939325b59STrilok Soni } 61039325b59STrilok Soni 61139325b59STrilok Soni kp->ctrl_reg = ctrl_val; 61239325b59STrilok Soni 61339325b59STrilok Soni rc = input_register_device(kp->input); 61439325b59STrilok Soni if (rc < 0) { 61539325b59STrilok Soni dev_err(&pdev->dev, "unable to register keypad input device\n"); 61639325b59STrilok Soni return rc; 61739325b59STrilok Soni } 61839325b59STrilok Soni 61986ea5e6bSStephen Boyd device_init_wakeup(&pdev->dev, wakeup); 62039325b59STrilok Soni 62139325b59STrilok Soni return 0; 62239325b59STrilok Soni } 62339325b59STrilok Soni 62439325b59STrilok Soni #ifdef CONFIG_PM_SLEEP 62539325b59STrilok Soni static int pmic8xxx_kp_suspend(struct device *dev) 62639325b59STrilok Soni { 62739325b59STrilok Soni struct platform_device *pdev = to_platform_device(dev); 62839325b59STrilok Soni struct pmic8xxx_kp *kp = platform_get_drvdata(pdev); 62939325b59STrilok Soni struct input_dev *input_dev = kp->input; 63039325b59STrilok Soni 63139325b59STrilok Soni if (device_may_wakeup(dev)) { 63239325b59STrilok Soni enable_irq_wake(kp->key_sense_irq); 63339325b59STrilok Soni } else { 63439325b59STrilok Soni mutex_lock(&input_dev->mutex); 63539325b59STrilok Soni 636*d69f0a43SAndrzej Pietrasiewicz if (input_device_enabled(input_dev)) 63739325b59STrilok Soni pmic8xxx_kp_disable(kp); 63839325b59STrilok Soni 63939325b59STrilok Soni mutex_unlock(&input_dev->mutex); 64039325b59STrilok Soni } 64139325b59STrilok Soni 64239325b59STrilok Soni return 0; 64339325b59STrilok Soni } 64439325b59STrilok Soni 64539325b59STrilok Soni static int pmic8xxx_kp_resume(struct device *dev) 64639325b59STrilok Soni { 64739325b59STrilok Soni struct platform_device *pdev = to_platform_device(dev); 64839325b59STrilok Soni struct pmic8xxx_kp *kp = platform_get_drvdata(pdev); 64939325b59STrilok Soni struct input_dev *input_dev = kp->input; 65039325b59STrilok Soni 65139325b59STrilok Soni if (device_may_wakeup(dev)) { 65239325b59STrilok Soni disable_irq_wake(kp->key_sense_irq); 65339325b59STrilok Soni } else { 65439325b59STrilok Soni mutex_lock(&input_dev->mutex); 65539325b59STrilok Soni 656*d69f0a43SAndrzej Pietrasiewicz if (input_device_enabled(input_dev)) 65739325b59STrilok Soni pmic8xxx_kp_enable(kp); 65839325b59STrilok Soni 65939325b59STrilok Soni mutex_unlock(&input_dev->mutex); 66039325b59STrilok Soni } 66139325b59STrilok Soni 66239325b59STrilok Soni return 0; 66339325b59STrilok Soni } 66439325b59STrilok Soni #endif 66539325b59STrilok Soni 66639325b59STrilok Soni static SIMPLE_DEV_PM_OPS(pm8xxx_kp_pm_ops, 66739325b59STrilok Soni pmic8xxx_kp_suspend, pmic8xxx_kp_resume); 66839325b59STrilok Soni 66986ea5e6bSStephen Boyd static const struct of_device_id pm8xxx_match_table[] = { 67086ea5e6bSStephen Boyd { .compatible = "qcom,pm8058-keypad" }, 67186ea5e6bSStephen Boyd { .compatible = "qcom,pm8921-keypad" }, 67286ea5e6bSStephen Boyd { } 67386ea5e6bSStephen Boyd }; 67486ea5e6bSStephen Boyd MODULE_DEVICE_TABLE(of, pm8xxx_match_table); 67586ea5e6bSStephen Boyd 67639325b59STrilok Soni static struct platform_driver pmic8xxx_kp_driver = { 67739325b59STrilok Soni .probe = pmic8xxx_kp_probe, 67839325b59STrilok Soni .driver = { 67986ea5e6bSStephen Boyd .name = "pm8xxx-keypad", 68039325b59STrilok Soni .pm = &pm8xxx_kp_pm_ops, 68186ea5e6bSStephen Boyd .of_match_table = pm8xxx_match_table, 68239325b59STrilok Soni }, 68339325b59STrilok Soni }; 6845146c84fSJJ Ding module_platform_driver(pmic8xxx_kp_driver); 68539325b59STrilok Soni 68639325b59STrilok Soni MODULE_LICENSE("GPL v2"); 68739325b59STrilok Soni MODULE_DESCRIPTION("PMIC8XXX keypad driver"); 68839325b59STrilok Soni MODULE_ALIAS("platform:pmic8xxx_keypad"); 68939325b59STrilok Soni MODULE_AUTHOR("Trilok Soni <tsoni@codeaurora.org>"); 690