^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) * Copyright (C) 2014 Broadcom Corporation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * This program is free software; you can redistribute it and/or
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * modify it under the terms of the GNU General Public License as
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * published by the Free Software Foundation version 2.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * This program is distributed "as is" WITHOUT ANY WARRANTY of any
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * kind, whether express or implied; without even the implied warranty
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * GNU General Public License for more details.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/bitops.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/clk.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/gfp.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/input.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/input/matrix_keypad.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/of.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/stddef.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #define DEFAULT_CLK_HZ 31250
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #define MAX_ROWS 8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #define MAX_COLS 8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) /* Register/field definitions */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #define KPCR_OFFSET 0x00000080
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #define KPCR_MODE 0x00000002
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #define KPCR_MODE_SHIFT 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #define KPCR_MODE_MASK 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #define KPCR_ENABLE 0x00000001
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #define KPCR_STATUSFILTERENABLE 0x00008000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #define KPCR_STATUSFILTERTYPE_SHIFT 12
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #define KPCR_COLFILTERENABLE 0x00000800
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #define KPCR_COLFILTERTYPE_SHIFT 8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #define KPCR_ROWWIDTH_SHIFT 20
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) #define KPCR_COLUMNWIDTH_SHIFT 16
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #define KPIOR_OFFSET 0x00000084
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) #define KPIOR_ROWOCONTRL_SHIFT 24
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) #define KPIOR_ROWOCONTRL_MASK 0xFF000000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) #define KPIOR_COLUMNOCONTRL_SHIFT 16
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) #define KPIOR_COLUMNOCONTRL_MASK 0x00FF0000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) #define KPIOR_COLUMN_IO_DATA_SHIFT 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) #define KPEMR0_OFFSET 0x00000090
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) #define KPEMR1_OFFSET 0x00000094
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) #define KPEMR2_OFFSET 0x00000098
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) #define KPEMR3_OFFSET 0x0000009C
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) #define KPEMR_EDGETYPE_BOTH 3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) #define KPSSR0_OFFSET 0x000000A0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) #define KPSSR1_OFFSET 0x000000A4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) #define KPSSRN_OFFSET(reg_n) (KPSSR0_OFFSET + 4 * (reg_n))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) #define KPIMR0_OFFSET 0x000000B0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) #define KPIMR1_OFFSET 0x000000B4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) #define KPICR0_OFFSET 0x000000B8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) #define KPICR1_OFFSET 0x000000BC
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) #define KPICRN_OFFSET(reg_n) (KPICR0_OFFSET + 4 * (reg_n))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) #define KPISR0_OFFSET 0x000000C0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) #define KPISR1_OFFSET 0x000000C4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) #define KPCR_STATUSFILTERTYPE_MAX 7
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) #define KPCR_COLFILTERTYPE_MAX 7
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) /* Macros to determine the row/column from a bit that is set in SSR0/1. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) #define BIT_TO_ROW_SSRN(bit_nr, reg_n) (((bit_nr) >> 3) + 4 * (reg_n))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) #define BIT_TO_COL(bit_nr) ((bit_nr) % 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) /* Structure representing various run-time entities */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) struct bcm_kp {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) void __iomem *base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) int irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) struct clk *clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) struct input_dev *input_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) unsigned long last_state[2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) unsigned int n_rows;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) unsigned int n_cols;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) u32 kpcr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) u32 kpior;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) u32 kpemr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) u32 imr0_val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) u32 imr1_val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) * Returns the keycode from the input device keymap given the row and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) * column.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) static int bcm_kp_get_keycode(struct bcm_kp *kp, int row, int col)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) unsigned int row_shift = get_count_order(kp->n_cols);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) unsigned short *keymap = kp->input_dev->keycode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) return keymap[MATRIX_SCAN_CODE(row, col, row_shift)];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) static void bcm_kp_report_keys(struct bcm_kp *kp, int reg_num, int pull_mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) unsigned long state, change;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) int bit_nr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) int key_press;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) int row, col;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) unsigned int keycode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) /* Clear interrupts */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) writel(0xFFFFFFFF, kp->base + KPICRN_OFFSET(reg_num));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) state = readl(kp->base + KPSSRN_OFFSET(reg_num));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) change = kp->last_state[reg_num] ^ state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) kp->last_state[reg_num] = state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) for_each_set_bit(bit_nr, &change, BITS_PER_LONG) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) key_press = state & BIT(bit_nr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) /* The meaning of SSR register depends on pull mode. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) key_press = pull_mode ? !key_press : key_press;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) row = BIT_TO_ROW_SSRN(bit_nr, reg_num);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) col = BIT_TO_COL(bit_nr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) keycode = bcm_kp_get_keycode(kp, row, col);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) input_report_key(kp->input_dev, keycode, key_press);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) static irqreturn_t bcm_kp_isr_thread(int irq, void *dev_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) struct bcm_kp *kp = dev_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) int pull_mode = (kp->kpcr >> KPCR_MODE_SHIFT) & KPCR_MODE_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) int reg_num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) for (reg_num = 0; reg_num <= 1; reg_num++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) bcm_kp_report_keys(kp, reg_num, pull_mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) input_sync(kp->input_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) static int bcm_kp_start(struct bcm_kp *kp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) if (kp->clk) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) error = clk_prepare_enable(kp->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) writel(kp->kpior, kp->base + KPIOR_OFFSET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) writel(kp->imr0_val, kp->base + KPIMR0_OFFSET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) writel(kp->imr1_val, kp->base + KPIMR1_OFFSET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) writel(kp->kpemr, kp->base + KPEMR0_OFFSET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) writel(kp->kpemr, kp->base + KPEMR1_OFFSET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) writel(kp->kpemr, kp->base + KPEMR2_OFFSET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) writel(kp->kpemr, kp->base + KPEMR3_OFFSET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) writel(0xFFFFFFFF, kp->base + KPICR0_OFFSET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) writel(0xFFFFFFFF, kp->base + KPICR1_OFFSET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) kp->last_state[0] = readl(kp->base + KPSSR0_OFFSET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) kp->last_state[0] = readl(kp->base + KPSSR1_OFFSET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) writel(kp->kpcr | KPCR_ENABLE, kp->base + KPCR_OFFSET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) static void bcm_kp_stop(const struct bcm_kp *kp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) u32 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) val = readl(kp->base + KPCR_OFFSET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) val &= ~KPCR_ENABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) writel(0, kp->base + KPCR_OFFSET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) writel(0, kp->base + KPIMR0_OFFSET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) writel(0, kp->base + KPIMR1_OFFSET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) writel(0xFFFFFFFF, kp->base + KPICR0_OFFSET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) writel(0xFFFFFFFF, kp->base + KPICR1_OFFSET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) if (kp->clk)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) clk_disable_unprepare(kp->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) static int bcm_kp_open(struct input_dev *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) struct bcm_kp *kp = input_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) return bcm_kp_start(kp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) static void bcm_kp_close(struct input_dev *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) struct bcm_kp *kp = input_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) bcm_kp_stop(kp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) static int bcm_kp_matrix_key_parse_dt(struct bcm_kp *kp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) struct device *dev = kp->input_dev->dev.parent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) struct device_node *np = dev->of_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) unsigned int dt_val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) unsigned int num_rows, col_mask, rows_set;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) /* Initialize the KPCR Keypad Configuration Register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) kp->kpcr = KPCR_STATUSFILTERENABLE | KPCR_COLFILTERENABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) error = matrix_keypad_parse_properties(dev, &kp->n_rows, &kp->n_cols);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) dev_err(dev, "failed to parse kp params\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) /* Set row width for the ASIC block. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) kp->kpcr |= (kp->n_rows - 1) << KPCR_ROWWIDTH_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) /* Set column width for the ASIC block. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) kp->kpcr |= (kp->n_cols - 1) << KPCR_COLUMNWIDTH_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) /* Configure the IMR registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) * IMR registers contain interrupt enable bits for 8x8 matrix
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) * IMR0 register format: <row3> <row2> <row1> <row0>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) * IMR1 register format: <row7> <row6> <row5> <row4>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) col_mask = (1 << (kp->n_cols)) - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) num_rows = kp->n_rows;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) /* Set column bits in rows 0 to 3 in IMR0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) kp->imr0_val = col_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) rows_set = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) while (--num_rows && rows_set++ < 4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) kp->imr0_val |= kp->imr0_val << MAX_COLS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) /* Set column bits in rows 4 to 7 in IMR1 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) kp->imr1_val = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) if (num_rows) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) kp->imr1_val = col_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) while (--num_rows)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) kp->imr1_val |= kp->imr1_val << MAX_COLS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) /* Initialize the KPEMR Keypress Edge Mode Registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) /* Trigger on both edges */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) kp->kpemr = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) for (i = 0; i <= 30; i += 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) kp->kpemr |= (KPEMR_EDGETYPE_BOTH << i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) * Obtain the Status filter debounce value and verify against the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) * possible values specified in the DT binding.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) of_property_read_u32(np, "status-debounce-filter-period", &dt_val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) if (dt_val > KPCR_STATUSFILTERTYPE_MAX) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) dev_err(dev, "Invalid Status filter debounce value %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) dt_val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) kp->kpcr |= dt_val << KPCR_STATUSFILTERTYPE_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) * Obtain the Column filter debounce value and verify against the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) * possible values specified in the DT binding.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) of_property_read_u32(np, "col-debounce-filter-period", &dt_val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) if (dt_val > KPCR_COLFILTERTYPE_MAX) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) dev_err(dev, "Invalid Column filter debounce value %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) dt_val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) kp->kpcr |= dt_val << KPCR_COLFILTERTYPE_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) * Determine between the row and column,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) * which should be configured as output.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) if (of_property_read_bool(np, "row-output-enabled")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) * Set RowOContrl or ColumnOContrl in KPIOR
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) * to the number of pins to drive as outputs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) kp->kpior = ((1 << kp->n_rows) - 1) <<
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) KPIOR_ROWOCONTRL_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) kp->kpior = ((1 << kp->n_cols) - 1) <<
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) KPIOR_COLUMNOCONTRL_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) * Determine if the scan pull up needs to be enabled
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) if (of_property_read_bool(np, "pull-up-enabled"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) kp->kpcr |= KPCR_MODE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) dev_dbg(dev, "n_rows=%d n_col=%d kpcr=%x kpior=%x kpemr=%x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) kp->n_rows, kp->n_cols,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) kp->kpcr, kp->kpior, kp->kpemr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) static int bcm_kp_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) struct bcm_kp *kp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) struct input_dev *input_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) struct resource *res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) kp = devm_kzalloc(&pdev->dev, sizeof(*kp), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) if (!kp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) input_dev = devm_input_allocate_device(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) if (!input_dev) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) dev_err(&pdev->dev, "failed to allocate the input device\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) __set_bit(EV_KEY, input_dev->evbit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) /* Enable auto repeat feature of Linux input subsystem */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) if (of_property_read_bool(pdev->dev.of_node, "autorepeat"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) __set_bit(EV_REP, input_dev->evbit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) input_dev->name = pdev->name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) input_dev->phys = "keypad/input0";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) input_dev->dev.parent = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) input_dev->open = bcm_kp_open;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) input_dev->close = bcm_kp_close;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) input_dev->id.bustype = BUS_HOST;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) input_dev->id.vendor = 0x0001;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) input_dev->id.product = 0x0001;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) input_dev->id.version = 0x0100;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) input_set_drvdata(input_dev, kp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) kp->input_dev = input_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) error = bcm_kp_matrix_key_parse_dt(kp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) error = matrix_keypad_build_keymap(NULL, NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) kp->n_rows, kp->n_cols,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) NULL, input_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) dev_err(&pdev->dev, "failed to build keymap\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) /* Get the KEYPAD base address */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) if (!res) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) dev_err(&pdev->dev, "Missing keypad base address resource\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) kp->base = devm_ioremap_resource(&pdev->dev, res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) if (IS_ERR(kp->base))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) return PTR_ERR(kp->base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) /* Enable clock */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) kp->clk = devm_clk_get(&pdev->dev, "peri_clk");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) if (IS_ERR(kp->clk)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) error = PTR_ERR(kp->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) if (error != -ENOENT) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) if (error != -EPROBE_DEFER)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) dev_err(&pdev->dev, "Failed to get clock\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) dev_dbg(&pdev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) "No clock specified. Assuming it's enabled\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) kp->clk = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) unsigned int desired_rate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) long actual_rate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) error = of_property_read_u32(pdev->dev.of_node,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) "clock-frequency", &desired_rate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) if (error < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) desired_rate = DEFAULT_CLK_HZ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) actual_rate = clk_round_rate(kp->clk, desired_rate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) if (actual_rate <= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) error = clk_set_rate(kp->clk, actual_rate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) error = clk_prepare_enable(kp->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) /* Put the kp into a known sane state */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) bcm_kp_stop(kp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) kp->irq = platform_get_irq(pdev, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) if (kp->irq < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) error = devm_request_threaded_irq(&pdev->dev, kp->irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) NULL, bcm_kp_isr_thread,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) IRQF_ONESHOT, pdev->name, kp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) dev_err(&pdev->dev, "failed to request IRQ\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) error = input_register_device(input_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) dev_err(&pdev->dev, "failed to register input device\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) static const struct of_device_id bcm_kp_of_match[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) { .compatible = "brcm,bcm-keypad" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) { },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) MODULE_DEVICE_TABLE(of, bcm_kp_of_match);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) static struct platform_driver bcm_kp_device_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) .probe = bcm_kp_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) .name = "bcm-keypad",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) .of_match_table = of_match_ptr(bcm_kp_of_match),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) module_platform_driver(bcm_kp_device_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) MODULE_AUTHOR("Broadcom Corporation");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) MODULE_DESCRIPTION("BCM Keypad Driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) MODULE_LICENSE("GPL v2");