cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

tc3589x-keypad.c (13542B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (C) ST-Ericsson SA 2010
      4 *
      5 * Author: Jayeeta Banerjee <jayeeta.banerjee@stericsson.com>
      6 * Author: Sundar Iyer <sundar.iyer@stericsson.com>
      7 *
      8 * TC35893 MFD Keypad Controller driver
      9 */
     10
     11#include <linux/module.h>
     12#include <linux/interrupt.h>
     13#include <linux/input.h>
     14#include <linux/platform_device.h>
     15#include <linux/input/matrix_keypad.h>
     16#include <linux/i2c.h>
     17#include <linux/slab.h>
     18#include <linux/mfd/tc3589x.h>
     19#include <linux/device.h>
     20
     21/* Maximum supported keypad matrix row/columns size */
     22#define TC3589x_MAX_KPROW               8
     23#define TC3589x_MAX_KPCOL               12
     24
     25/* keypad related Constants */
     26#define TC3589x_MAX_DEBOUNCE_SETTLE     0xFF
     27#define DEDICATED_KEY_VAL		0xFF
     28
     29/* Pull up/down masks */
     30#define TC3589x_NO_PULL_MASK		0x0
     31#define TC3589x_PULL_DOWN_MASK		0x1
     32#define TC3589x_PULL_UP_MASK		0x2
     33#define TC3589x_PULLUP_ALL_MASK		0xAA
     34#define TC3589x_IO_PULL_VAL(index, mask)	((mask)<<((index)%4)*2)
     35
     36/* Bit masks for IOCFG register */
     37#define IOCFG_BALLCFG		0x01
     38#define IOCFG_IG		0x08
     39
     40#define KP_EVCODE_COL_MASK	0x0F
     41#define KP_EVCODE_ROW_MASK	0x70
     42#define KP_RELEASE_EVT_MASK	0x80
     43
     44#define KP_ROW_SHIFT		4
     45
     46#define KP_NO_VALID_KEY_MASK	0x7F
     47
     48/* bit masks for RESTCTRL register */
     49#define TC3589x_KBDRST		0x2
     50#define TC3589x_IRQRST		0x10
     51#define TC3589x_RESET_ALL	0x1B
     52
     53/* KBDMFS register bit mask */
     54#define TC3589x_KBDMFS_EN	0x1
     55
     56/* CLKEN register bitmask */
     57#define KPD_CLK_EN		0x1
     58
     59/* RSTINTCLR register bit mask */
     60#define IRQ_CLEAR		0x1
     61
     62/* bit masks for keyboard interrupts*/
     63#define TC3589x_EVT_LOSS_INT	0x8
     64#define TC3589x_EVT_INT		0x4
     65#define TC3589x_KBD_LOSS_INT	0x2
     66#define TC3589x_KBD_INT		0x1
     67
     68/* bit masks for keyboard interrupt clear*/
     69#define TC3589x_EVT_INT_CLR	0x2
     70#define TC3589x_KBD_INT_CLR	0x1
     71
     72/**
     73 * struct tc35893_keypad_platform_data - platform specific keypad data
     74 * @keymap_data:        matrix scan code table for keycodes
     75 * @krow:               mask for available rows, value is 0xFF
     76 * @kcol:               mask for available columns, value is 0xFF
     77 * @debounce_period:    platform specific debounce time
     78 * @settle_time:        platform specific settle down time
     79 * @irqtype:            type of interrupt, falling or rising edge
     80 * @enable_wakeup:      specifies if keypad event can wake up system from sleep
     81 * @no_autorepeat:      flag for auto repetition
     82 */
     83struct tc3589x_keypad_platform_data {
     84	const struct matrix_keymap_data *keymap_data;
     85	u8                      krow;
     86	u8                      kcol;
     87	u8                      debounce_period;
     88	u8                      settle_time;
     89	unsigned long           irqtype;
     90	bool                    enable_wakeup;
     91	bool                    no_autorepeat;
     92};
     93
     94/**
     95 * struct tc_keypad - data structure used by keypad driver
     96 * @tc3589x:    pointer to tc35893
     97 * @input:      pointer to input device object
     98 * @board:      keypad platform device
     99 * @krow:	number of rows
    100 * @kcol:	number of columns
    101 * @keymap:     matrix scan code table for keycodes
    102 * @keypad_stopped: holds keypad status
    103 */
    104struct tc_keypad {
    105	struct tc3589x *tc3589x;
    106	struct input_dev *input;
    107	const struct tc3589x_keypad_platform_data *board;
    108	unsigned int krow;
    109	unsigned int kcol;
    110	unsigned short *keymap;
    111	bool keypad_stopped;
    112};
    113
    114static int tc3589x_keypad_init_key_hardware(struct tc_keypad *keypad)
    115{
    116	int ret;
    117	struct tc3589x *tc3589x = keypad->tc3589x;
    118	const struct tc3589x_keypad_platform_data *board = keypad->board;
    119
    120	/* validate platform configuration */
    121	if (board->kcol > TC3589x_MAX_KPCOL || board->krow > TC3589x_MAX_KPROW)
    122		return -EINVAL;
    123
    124	/* configure KBDSIZE 4 LSbits for cols and 4 MSbits for rows */
    125	ret = tc3589x_reg_write(tc3589x, TC3589x_KBDSIZE,
    126			(board->krow << KP_ROW_SHIFT) | board->kcol);
    127	if (ret < 0)
    128		return ret;
    129
    130	/* configure dedicated key config, no dedicated key selected */
    131	ret = tc3589x_reg_write(tc3589x, TC3589x_KBCFG_LSB, DEDICATED_KEY_VAL);
    132	if (ret < 0)
    133		return ret;
    134
    135	ret = tc3589x_reg_write(tc3589x, TC3589x_KBCFG_MSB, DEDICATED_KEY_VAL);
    136	if (ret < 0)
    137		return ret;
    138
    139	/* Configure settle time */
    140	ret = tc3589x_reg_write(tc3589x, TC3589x_KBDSETTLE_REG,
    141				board->settle_time);
    142	if (ret < 0)
    143		return ret;
    144
    145	/* Configure debounce time */
    146	ret = tc3589x_reg_write(tc3589x, TC3589x_KBDBOUNCE,
    147				board->debounce_period);
    148	if (ret < 0)
    149		return ret;
    150
    151	/* Start of initialise keypad GPIOs */
    152	ret = tc3589x_set_bits(tc3589x, TC3589x_IOCFG, 0x0, IOCFG_IG);
    153	if (ret < 0)
    154		return ret;
    155
    156	/* Configure pull-up resistors for all row GPIOs */
    157	ret = tc3589x_reg_write(tc3589x, TC3589x_IOPULLCFG0_LSB,
    158					TC3589x_PULLUP_ALL_MASK);
    159	if (ret < 0)
    160		return ret;
    161
    162	ret = tc3589x_reg_write(tc3589x, TC3589x_IOPULLCFG0_MSB,
    163					TC3589x_PULLUP_ALL_MASK);
    164	if (ret < 0)
    165		return ret;
    166
    167	/* Configure pull-up resistors for all column GPIOs */
    168	ret = tc3589x_reg_write(tc3589x, TC3589x_IOPULLCFG1_LSB,
    169			TC3589x_PULLUP_ALL_MASK);
    170	if (ret < 0)
    171		return ret;
    172
    173	ret = tc3589x_reg_write(tc3589x, TC3589x_IOPULLCFG1_MSB,
    174			TC3589x_PULLUP_ALL_MASK);
    175	if (ret < 0)
    176		return ret;
    177
    178	ret = tc3589x_reg_write(tc3589x, TC3589x_IOPULLCFG2_LSB,
    179			TC3589x_PULLUP_ALL_MASK);
    180
    181	return ret;
    182}
    183
    184#define TC35893_DATA_REGS		4
    185#define TC35893_KEYCODE_FIFO_EMPTY	0x7f
    186#define TC35893_KEYCODE_FIFO_CLEAR	0xff
    187#define TC35893_KEYPAD_ROW_SHIFT	0x3
    188
    189static irqreturn_t tc3589x_keypad_irq(int irq, void *dev)
    190{
    191	struct tc_keypad *keypad = dev;
    192	struct tc3589x *tc3589x = keypad->tc3589x;
    193	u8 i, row_index, col_index, kbd_code, up;
    194	u8 code;
    195
    196	for (i = 0; i < TC35893_DATA_REGS * 2; i++) {
    197		kbd_code = tc3589x_reg_read(tc3589x, TC3589x_EVTCODE_FIFO);
    198
    199		/* loop till fifo is empty and no more keys are pressed */
    200		if (kbd_code == TC35893_KEYCODE_FIFO_EMPTY ||
    201				kbd_code == TC35893_KEYCODE_FIFO_CLEAR)
    202			continue;
    203
    204		/* valid key is found */
    205		col_index = kbd_code & KP_EVCODE_COL_MASK;
    206		row_index = (kbd_code & KP_EVCODE_ROW_MASK) >> KP_ROW_SHIFT;
    207		code = MATRIX_SCAN_CODE(row_index, col_index,
    208						TC35893_KEYPAD_ROW_SHIFT);
    209		up = kbd_code & KP_RELEASE_EVT_MASK;
    210
    211		input_event(keypad->input, EV_MSC, MSC_SCAN, code);
    212		input_report_key(keypad->input, keypad->keymap[code], !up);
    213		input_sync(keypad->input);
    214	}
    215
    216	/* clear IRQ */
    217	tc3589x_set_bits(tc3589x, TC3589x_KBDIC,
    218			0x0, TC3589x_EVT_INT_CLR | TC3589x_KBD_INT_CLR);
    219	/* enable IRQ */
    220	tc3589x_set_bits(tc3589x, TC3589x_KBDMSK,
    221			0x0, TC3589x_EVT_LOSS_INT | TC3589x_EVT_INT);
    222
    223	return IRQ_HANDLED;
    224}
    225
    226static int tc3589x_keypad_enable(struct tc_keypad *keypad)
    227{
    228	struct tc3589x *tc3589x = keypad->tc3589x;
    229	int ret;
    230
    231	/* pull the keypad module out of reset */
    232	ret = tc3589x_set_bits(tc3589x, TC3589x_RSTCTRL, TC3589x_KBDRST, 0x0);
    233	if (ret < 0)
    234		return ret;
    235
    236	/* configure KBDMFS */
    237	ret = tc3589x_set_bits(tc3589x, TC3589x_KBDMFS, 0x0, TC3589x_KBDMFS_EN);
    238	if (ret < 0)
    239		return ret;
    240
    241	/* enable the keypad clock */
    242	ret = tc3589x_set_bits(tc3589x, TC3589x_CLKEN, 0x0, KPD_CLK_EN);
    243	if (ret < 0)
    244		return ret;
    245
    246	/* clear pending IRQs */
    247	ret =  tc3589x_set_bits(tc3589x, TC3589x_RSTINTCLR, 0x0, 0x1);
    248	if (ret < 0)
    249		return ret;
    250
    251	/* enable the IRQs */
    252	ret = tc3589x_set_bits(tc3589x, TC3589x_KBDMSK, 0x0,
    253					TC3589x_EVT_LOSS_INT | TC3589x_EVT_INT);
    254	if (ret < 0)
    255		return ret;
    256
    257	keypad->keypad_stopped = false;
    258
    259	return ret;
    260}
    261
    262static int tc3589x_keypad_disable(struct tc_keypad *keypad)
    263{
    264	struct tc3589x *tc3589x = keypad->tc3589x;
    265	int ret;
    266
    267	/* clear IRQ */
    268	ret = tc3589x_set_bits(tc3589x, TC3589x_KBDIC,
    269			0x0, TC3589x_EVT_INT_CLR | TC3589x_KBD_INT_CLR);
    270	if (ret < 0)
    271		return ret;
    272
    273	/* disable all interrupts */
    274	ret = tc3589x_set_bits(tc3589x, TC3589x_KBDMSK,
    275			~(TC3589x_EVT_LOSS_INT | TC3589x_EVT_INT), 0x0);
    276	if (ret < 0)
    277		return ret;
    278
    279	/* disable the keypad module */
    280	ret = tc3589x_set_bits(tc3589x, TC3589x_CLKEN, 0x1, 0x0);
    281	if (ret < 0)
    282		return ret;
    283
    284	/* put the keypad module into reset */
    285	ret = tc3589x_set_bits(tc3589x, TC3589x_RSTCTRL, TC3589x_KBDRST, 0x1);
    286
    287	keypad->keypad_stopped = true;
    288
    289	return ret;
    290}
    291
    292static int tc3589x_keypad_open(struct input_dev *input)
    293{
    294	int error;
    295	struct tc_keypad *keypad = input_get_drvdata(input);
    296
    297	/* enable the keypad module */
    298	error = tc3589x_keypad_enable(keypad);
    299	if (error < 0) {
    300		dev_err(&input->dev, "failed to enable keypad module\n");
    301		return error;
    302	}
    303
    304	error = tc3589x_keypad_init_key_hardware(keypad);
    305	if (error < 0) {
    306		dev_err(&input->dev, "failed to configure keypad module\n");
    307		return error;
    308	}
    309
    310	return 0;
    311}
    312
    313static void tc3589x_keypad_close(struct input_dev *input)
    314{
    315	struct tc_keypad *keypad = input_get_drvdata(input);
    316
    317	/* disable the keypad module */
    318	tc3589x_keypad_disable(keypad);
    319}
    320
    321static const struct tc3589x_keypad_platform_data *
    322tc3589x_keypad_of_probe(struct device *dev)
    323{
    324	struct device_node *np = dev->of_node;
    325	struct tc3589x_keypad_platform_data *plat;
    326	u32 cols, rows;
    327	u32 debounce_ms;
    328	int proplen;
    329
    330	if (!np)
    331		return ERR_PTR(-ENODEV);
    332
    333	plat = devm_kzalloc(dev, sizeof(*plat), GFP_KERNEL);
    334	if (!plat)
    335		return ERR_PTR(-ENOMEM);
    336
    337	of_property_read_u32(np, "keypad,num-columns", &cols);
    338	of_property_read_u32(np, "keypad,num-rows", &rows);
    339	plat->kcol = (u8) cols;
    340	plat->krow = (u8) rows;
    341	if (!plat->krow || !plat->kcol ||
    342	     plat->krow > TC_KPD_ROWS || plat->kcol > TC_KPD_COLUMNS) {
    343		dev_err(dev,
    344			"keypad columns/rows not properly specified (%ux%u)\n",
    345			plat->kcol, plat->krow);
    346		return ERR_PTR(-EINVAL);
    347	}
    348
    349	if (!of_get_property(np, "linux,keymap", &proplen)) {
    350		dev_err(dev, "property linux,keymap not found\n");
    351		return ERR_PTR(-ENOENT);
    352	}
    353
    354	plat->no_autorepeat = of_property_read_bool(np, "linux,no-autorepeat");
    355
    356	plat->enable_wakeup = of_property_read_bool(np, "wakeup-source") ||
    357			      /* legacy name */
    358			      of_property_read_bool(np, "linux,wakeup");
    359
    360	/* The custom delay format is ms/16 */
    361	of_property_read_u32(np, "debounce-delay-ms", &debounce_ms);
    362	if (debounce_ms)
    363		plat->debounce_period = debounce_ms * 16;
    364	else
    365		plat->debounce_period = TC_KPD_DEBOUNCE_PERIOD;
    366
    367	plat->settle_time = TC_KPD_SETTLE_TIME;
    368	/* FIXME: should be property of the IRQ resource? */
    369	plat->irqtype = IRQF_TRIGGER_FALLING;
    370
    371	return plat;
    372}
    373
    374static int tc3589x_keypad_probe(struct platform_device *pdev)
    375{
    376	struct tc3589x *tc3589x = dev_get_drvdata(pdev->dev.parent);
    377	struct tc_keypad *keypad;
    378	struct input_dev *input;
    379	const struct tc3589x_keypad_platform_data *plat;
    380	int error, irq;
    381
    382	plat = tc3589x_keypad_of_probe(&pdev->dev);
    383	if (IS_ERR(plat)) {
    384		dev_err(&pdev->dev, "invalid keypad platform data\n");
    385		return PTR_ERR(plat);
    386	}
    387
    388	irq = platform_get_irq(pdev, 0);
    389	if (irq < 0)
    390		return irq;
    391
    392	keypad = devm_kzalloc(&pdev->dev, sizeof(struct tc_keypad),
    393			      GFP_KERNEL);
    394	if (!keypad)
    395		return -ENOMEM;
    396
    397	input = devm_input_allocate_device(&pdev->dev);
    398	if (!input) {
    399		dev_err(&pdev->dev, "failed to allocate input device\n");
    400		return -ENOMEM;
    401	}
    402
    403	keypad->board = plat;
    404	keypad->input = input;
    405	keypad->tc3589x = tc3589x;
    406
    407	input->id.bustype = BUS_I2C;
    408	input->name = pdev->name;
    409	input->dev.parent = &pdev->dev;
    410
    411	input->open = tc3589x_keypad_open;
    412	input->close = tc3589x_keypad_close;
    413
    414	error = matrix_keypad_build_keymap(plat->keymap_data, NULL,
    415					   TC3589x_MAX_KPROW, TC3589x_MAX_KPCOL,
    416					   NULL, input);
    417	if (error) {
    418		dev_err(&pdev->dev, "Failed to build keymap\n");
    419		return error;
    420	}
    421
    422	keypad->keymap = input->keycode;
    423
    424	input_set_capability(input, EV_MSC, MSC_SCAN);
    425	if (!plat->no_autorepeat)
    426		__set_bit(EV_REP, input->evbit);
    427
    428	input_set_drvdata(input, keypad);
    429
    430	tc3589x_keypad_disable(keypad);
    431
    432	error = devm_request_threaded_irq(&pdev->dev, irq,
    433					  NULL, tc3589x_keypad_irq,
    434					  plat->irqtype | IRQF_ONESHOT,
    435					  "tc3589x-keypad", keypad);
    436	if (error) {
    437		dev_err(&pdev->dev,
    438				"Could not allocate irq %d,error %d\n",
    439				irq, error);
    440		return error;
    441	}
    442
    443	error = input_register_device(input);
    444	if (error) {
    445		dev_err(&pdev->dev, "Could not register input device\n");
    446		return error;
    447	}
    448
    449	/* let platform decide if keypad is a wakeup source or not */
    450	device_init_wakeup(&pdev->dev, plat->enable_wakeup);
    451	device_set_wakeup_capable(&pdev->dev, plat->enable_wakeup);
    452
    453	platform_set_drvdata(pdev, keypad);
    454
    455	return 0;
    456}
    457
    458#ifdef CONFIG_PM_SLEEP
    459static int tc3589x_keypad_suspend(struct device *dev)
    460{
    461	struct platform_device *pdev = to_platform_device(dev);
    462	struct tc_keypad *keypad = platform_get_drvdata(pdev);
    463	int irq = platform_get_irq(pdev, 0);
    464
    465	/* keypad is already off; we do nothing */
    466	if (keypad->keypad_stopped)
    467		return 0;
    468
    469	/* if device is not a wakeup source, disable it for powersave */
    470	if (!device_may_wakeup(&pdev->dev))
    471		tc3589x_keypad_disable(keypad);
    472	else
    473		enable_irq_wake(irq);
    474
    475	return 0;
    476}
    477
    478static int tc3589x_keypad_resume(struct device *dev)
    479{
    480	struct platform_device *pdev = to_platform_device(dev);
    481	struct tc_keypad *keypad = platform_get_drvdata(pdev);
    482	int irq = platform_get_irq(pdev, 0);
    483
    484	if (!keypad->keypad_stopped)
    485		return 0;
    486
    487	/* enable the device to resume normal operations */
    488	if (!device_may_wakeup(&pdev->dev))
    489		tc3589x_keypad_enable(keypad);
    490	else
    491		disable_irq_wake(irq);
    492
    493	return 0;
    494}
    495#endif
    496
    497static SIMPLE_DEV_PM_OPS(tc3589x_keypad_dev_pm_ops,
    498			 tc3589x_keypad_suspend, tc3589x_keypad_resume);
    499
    500static struct platform_driver tc3589x_keypad_driver = {
    501	.driver	= {
    502		.name	= "tc3589x-keypad",
    503		.pm	= &tc3589x_keypad_dev_pm_ops,
    504	},
    505	.probe	= tc3589x_keypad_probe,
    506};
    507module_platform_driver(tc3589x_keypad_driver);
    508
    509MODULE_LICENSE("GPL v2");
    510MODULE_AUTHOR("Jayeeta Banerjee/Sundar Iyer");
    511MODULE_DESCRIPTION("TC35893 Keypad Driver");
    512MODULE_ALIAS("platform:tc3589x-keypad");