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

st-keyscan.c (6562B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * STMicroelectronics Key Scanning driver
      4 *
      5 * Copyright (c) 2014 STMicroelectonics Ltd.
      6 * Author: Stuart Menefy <stuart.menefy@st.com>
      7 *
      8 * Based on sh_keysc.c, copyright 2008 Magnus Damm
      9 */
     10
     11#include <linux/module.h>
     12#include <linux/interrupt.h>
     13#include <linux/platform_device.h>
     14#include <linux/clk.h>
     15#include <linux/io.h>
     16#include <linux/input/matrix_keypad.h>
     17
     18#define ST_KEYSCAN_MAXKEYS 16
     19
     20#define KEYSCAN_CONFIG_OFF		0x0
     21#define KEYSCAN_CONFIG_ENABLE		0x1
     22#define KEYSCAN_DEBOUNCE_TIME_OFF	0x4
     23#define KEYSCAN_MATRIX_STATE_OFF	0x8
     24#define KEYSCAN_MATRIX_DIM_OFF		0xc
     25#define KEYSCAN_MATRIX_DIM_X_SHIFT	0x0
     26#define KEYSCAN_MATRIX_DIM_Y_SHIFT	0x2
     27
     28struct st_keyscan {
     29	void __iomem *base;
     30	int irq;
     31	struct clk *clk;
     32	struct input_dev *input_dev;
     33	unsigned long last_state;
     34	unsigned int n_rows;
     35	unsigned int n_cols;
     36	unsigned int debounce_us;
     37};
     38
     39static irqreturn_t keyscan_isr(int irq, void *dev_id)
     40{
     41	struct st_keyscan *keypad = dev_id;
     42	unsigned short *keycode = keypad->input_dev->keycode;
     43	unsigned long state, change;
     44	int bit_nr;
     45
     46	state = readl(keypad->base + KEYSCAN_MATRIX_STATE_OFF) & 0xffff;
     47	change = keypad->last_state ^ state;
     48	keypad->last_state = state;
     49
     50	for_each_set_bit(bit_nr, &change, BITS_PER_LONG)
     51		input_report_key(keypad->input_dev,
     52				 keycode[bit_nr], state & BIT(bit_nr));
     53
     54	input_sync(keypad->input_dev);
     55
     56	return IRQ_HANDLED;
     57}
     58
     59static int keyscan_start(struct st_keyscan *keypad)
     60{
     61	int error;
     62
     63	error = clk_enable(keypad->clk);
     64	if (error)
     65		return error;
     66
     67	writel(keypad->debounce_us * (clk_get_rate(keypad->clk) / 1000000),
     68	       keypad->base + KEYSCAN_DEBOUNCE_TIME_OFF);
     69
     70	writel(((keypad->n_cols - 1) << KEYSCAN_MATRIX_DIM_X_SHIFT) |
     71	       ((keypad->n_rows - 1) << KEYSCAN_MATRIX_DIM_Y_SHIFT),
     72	       keypad->base + KEYSCAN_MATRIX_DIM_OFF);
     73
     74	writel(KEYSCAN_CONFIG_ENABLE, keypad->base + KEYSCAN_CONFIG_OFF);
     75
     76	return 0;
     77}
     78
     79static void keyscan_stop(struct st_keyscan *keypad)
     80{
     81	writel(0, keypad->base + KEYSCAN_CONFIG_OFF);
     82
     83	clk_disable(keypad->clk);
     84}
     85
     86static int keyscan_open(struct input_dev *dev)
     87{
     88	struct st_keyscan *keypad = input_get_drvdata(dev);
     89
     90	return keyscan_start(keypad);
     91}
     92
     93static void keyscan_close(struct input_dev *dev)
     94{
     95	struct st_keyscan *keypad = input_get_drvdata(dev);
     96
     97	keyscan_stop(keypad);
     98}
     99
    100static int keypad_matrix_key_parse_dt(struct st_keyscan *keypad_data)
    101{
    102	struct device *dev = keypad_data->input_dev->dev.parent;
    103	struct device_node *np = dev->of_node;
    104	int error;
    105
    106	error = matrix_keypad_parse_properties(dev, &keypad_data->n_rows,
    107					       &keypad_data->n_cols);
    108	if (error) {
    109		dev_err(dev, "failed to parse keypad params\n");
    110		return error;
    111	}
    112
    113	of_property_read_u32(np, "st,debounce-us", &keypad_data->debounce_us);
    114
    115	dev_dbg(dev, "n_rows=%d n_col=%d debounce=%d\n",
    116		keypad_data->n_rows, keypad_data->n_cols,
    117		keypad_data->debounce_us);
    118
    119	return 0;
    120}
    121
    122static int keyscan_probe(struct platform_device *pdev)
    123{
    124	struct st_keyscan *keypad_data;
    125	struct input_dev *input_dev;
    126	struct resource *res;
    127	int error;
    128
    129	if (!pdev->dev.of_node) {
    130		dev_err(&pdev->dev, "no DT data present\n");
    131		return -EINVAL;
    132	}
    133
    134	keypad_data = devm_kzalloc(&pdev->dev, sizeof(*keypad_data),
    135				   GFP_KERNEL);
    136	if (!keypad_data)
    137		return -ENOMEM;
    138
    139	input_dev = devm_input_allocate_device(&pdev->dev);
    140	if (!input_dev) {
    141		dev_err(&pdev->dev, "failed to allocate the input device\n");
    142		return -ENOMEM;
    143	}
    144
    145	input_dev->name = pdev->name;
    146	input_dev->phys = "keyscan-keys/input0";
    147	input_dev->dev.parent = &pdev->dev;
    148	input_dev->open = keyscan_open;
    149	input_dev->close = keyscan_close;
    150
    151	input_dev->id.bustype = BUS_HOST;
    152
    153	keypad_data->input_dev = input_dev;
    154
    155	error = keypad_matrix_key_parse_dt(keypad_data);
    156	if (error)
    157		return error;
    158
    159	error = matrix_keypad_build_keymap(NULL, NULL,
    160					   keypad_data->n_rows,
    161					   keypad_data->n_cols,
    162					   NULL, input_dev);
    163	if (error) {
    164		dev_err(&pdev->dev, "failed to build keymap\n");
    165		return error;
    166	}
    167
    168	input_set_drvdata(input_dev, keypad_data);
    169
    170	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    171	keypad_data->base = devm_ioremap_resource(&pdev->dev, res);
    172	if (IS_ERR(keypad_data->base))
    173		return PTR_ERR(keypad_data->base);
    174
    175	keypad_data->clk = devm_clk_get(&pdev->dev, NULL);
    176	if (IS_ERR(keypad_data->clk)) {
    177		dev_err(&pdev->dev, "cannot get clock\n");
    178		return PTR_ERR(keypad_data->clk);
    179	}
    180
    181	error = clk_enable(keypad_data->clk);
    182	if (error) {
    183		dev_err(&pdev->dev, "failed to enable clock\n");
    184		return error;
    185	}
    186
    187	keyscan_stop(keypad_data);
    188
    189	keypad_data->irq = platform_get_irq(pdev, 0);
    190	if (keypad_data->irq < 0)
    191		return -EINVAL;
    192
    193	error = devm_request_irq(&pdev->dev, keypad_data->irq, keyscan_isr, 0,
    194				 pdev->name, keypad_data);
    195	if (error) {
    196		dev_err(&pdev->dev, "failed to request IRQ\n");
    197		return error;
    198	}
    199
    200	error = input_register_device(input_dev);
    201	if (error) {
    202		dev_err(&pdev->dev, "failed to register input device\n");
    203		return error;
    204	}
    205
    206	platform_set_drvdata(pdev, keypad_data);
    207
    208	device_set_wakeup_capable(&pdev->dev, 1);
    209
    210	return 0;
    211}
    212
    213#ifdef CONFIG_PM_SLEEP
    214static int keyscan_suspend(struct device *dev)
    215{
    216	struct platform_device *pdev = to_platform_device(dev);
    217	struct st_keyscan *keypad = platform_get_drvdata(pdev);
    218	struct input_dev *input = keypad->input_dev;
    219
    220	mutex_lock(&input->mutex);
    221
    222	if (device_may_wakeup(dev))
    223		enable_irq_wake(keypad->irq);
    224	else if (input_device_enabled(input))
    225		keyscan_stop(keypad);
    226
    227	mutex_unlock(&input->mutex);
    228	return 0;
    229}
    230
    231static int keyscan_resume(struct device *dev)
    232{
    233	struct platform_device *pdev = to_platform_device(dev);
    234	struct st_keyscan *keypad = platform_get_drvdata(pdev);
    235	struct input_dev *input = keypad->input_dev;
    236	int retval = 0;
    237
    238	mutex_lock(&input->mutex);
    239
    240	if (device_may_wakeup(dev))
    241		disable_irq_wake(keypad->irq);
    242	else if (input_device_enabled(input))
    243		retval = keyscan_start(keypad);
    244
    245	mutex_unlock(&input->mutex);
    246	return retval;
    247}
    248#endif
    249
    250static SIMPLE_DEV_PM_OPS(keyscan_dev_pm_ops, keyscan_suspend, keyscan_resume);
    251
    252static const struct of_device_id keyscan_of_match[] = {
    253	{ .compatible = "st,sti-keyscan" },
    254	{ },
    255};
    256MODULE_DEVICE_TABLE(of, keyscan_of_match);
    257
    258static struct platform_driver keyscan_device_driver = {
    259	.probe		= keyscan_probe,
    260	.driver		= {
    261		.name	= "st-keyscan",
    262		.pm	= &keyscan_dev_pm_ops,
    263		.of_match_table = of_match_ptr(keyscan_of_match),
    264	}
    265};
    266
    267module_platform_driver(keyscan_device_driver);
    268
    269MODULE_AUTHOR("Stuart Menefy <stuart.menefy@st.com>");
    270MODULE_DESCRIPTION("STMicroelectronics keyscan device driver");
    271MODULE_LICENSE("GPL");