Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * STMicroelectronics Key Scanning driver
0004  *
0005  * Copyright (c) 2014 STMicroelectonics Ltd.
0006  * Author: Stuart Menefy <stuart.menefy@st.com>
0007  *
0008  * Based on sh_keysc.c, copyright 2008 Magnus Damm
0009  */
0010 
0011 #include <linux/module.h>
0012 #include <linux/interrupt.h>
0013 #include <linux/platform_device.h>
0014 #include <linux/clk.h>
0015 #include <linux/io.h>
0016 #include <linux/input/matrix_keypad.h>
0017 
0018 #define ST_KEYSCAN_MAXKEYS 16
0019 
0020 #define KEYSCAN_CONFIG_OFF      0x0
0021 #define KEYSCAN_CONFIG_ENABLE       0x1
0022 #define KEYSCAN_DEBOUNCE_TIME_OFF   0x4
0023 #define KEYSCAN_MATRIX_STATE_OFF    0x8
0024 #define KEYSCAN_MATRIX_DIM_OFF      0xc
0025 #define KEYSCAN_MATRIX_DIM_X_SHIFT  0x0
0026 #define KEYSCAN_MATRIX_DIM_Y_SHIFT  0x2
0027 
0028 struct st_keyscan {
0029     void __iomem *base;
0030     int irq;
0031     struct clk *clk;
0032     struct input_dev *input_dev;
0033     unsigned long last_state;
0034     unsigned int n_rows;
0035     unsigned int n_cols;
0036     unsigned int debounce_us;
0037 };
0038 
0039 static irqreturn_t keyscan_isr(int irq, void *dev_id)
0040 {
0041     struct st_keyscan *keypad = dev_id;
0042     unsigned short *keycode = keypad->input_dev->keycode;
0043     unsigned long state, change;
0044     int bit_nr;
0045 
0046     state = readl(keypad->base + KEYSCAN_MATRIX_STATE_OFF) & 0xffff;
0047     change = keypad->last_state ^ state;
0048     keypad->last_state = state;
0049 
0050     for_each_set_bit(bit_nr, &change, BITS_PER_LONG)
0051         input_report_key(keypad->input_dev,
0052                  keycode[bit_nr], state & BIT(bit_nr));
0053 
0054     input_sync(keypad->input_dev);
0055 
0056     return IRQ_HANDLED;
0057 }
0058 
0059 static int keyscan_start(struct st_keyscan *keypad)
0060 {
0061     int error;
0062 
0063     error = clk_enable(keypad->clk);
0064     if (error)
0065         return error;
0066 
0067     writel(keypad->debounce_us * (clk_get_rate(keypad->clk) / 1000000),
0068            keypad->base + KEYSCAN_DEBOUNCE_TIME_OFF);
0069 
0070     writel(((keypad->n_cols - 1) << KEYSCAN_MATRIX_DIM_X_SHIFT) |
0071            ((keypad->n_rows - 1) << KEYSCAN_MATRIX_DIM_Y_SHIFT),
0072            keypad->base + KEYSCAN_MATRIX_DIM_OFF);
0073 
0074     writel(KEYSCAN_CONFIG_ENABLE, keypad->base + KEYSCAN_CONFIG_OFF);
0075 
0076     return 0;
0077 }
0078 
0079 static void keyscan_stop(struct st_keyscan *keypad)
0080 {
0081     writel(0, keypad->base + KEYSCAN_CONFIG_OFF);
0082 
0083     clk_disable(keypad->clk);
0084 }
0085 
0086 static int keyscan_open(struct input_dev *dev)
0087 {
0088     struct st_keyscan *keypad = input_get_drvdata(dev);
0089 
0090     return keyscan_start(keypad);
0091 }
0092 
0093 static void keyscan_close(struct input_dev *dev)
0094 {
0095     struct st_keyscan *keypad = input_get_drvdata(dev);
0096 
0097     keyscan_stop(keypad);
0098 }
0099 
0100 static int keypad_matrix_key_parse_dt(struct st_keyscan *keypad_data)
0101 {
0102     struct device *dev = keypad_data->input_dev->dev.parent;
0103     struct device_node *np = dev->of_node;
0104     int error;
0105 
0106     error = matrix_keypad_parse_properties(dev, &keypad_data->n_rows,
0107                            &keypad_data->n_cols);
0108     if (error) {
0109         dev_err(dev, "failed to parse keypad params\n");
0110         return error;
0111     }
0112 
0113     of_property_read_u32(np, "st,debounce-us", &keypad_data->debounce_us);
0114 
0115     dev_dbg(dev, "n_rows=%d n_col=%d debounce=%d\n",
0116         keypad_data->n_rows, keypad_data->n_cols,
0117         keypad_data->debounce_us);
0118 
0119     return 0;
0120 }
0121 
0122 static int keyscan_probe(struct platform_device *pdev)
0123 {
0124     struct st_keyscan *keypad_data;
0125     struct input_dev *input_dev;
0126     struct resource *res;
0127     int error;
0128 
0129     if (!pdev->dev.of_node) {
0130         dev_err(&pdev->dev, "no DT data present\n");
0131         return -EINVAL;
0132     }
0133 
0134     keypad_data = devm_kzalloc(&pdev->dev, sizeof(*keypad_data),
0135                    GFP_KERNEL);
0136     if (!keypad_data)
0137         return -ENOMEM;
0138 
0139     input_dev = devm_input_allocate_device(&pdev->dev);
0140     if (!input_dev) {
0141         dev_err(&pdev->dev, "failed to allocate the input device\n");
0142         return -ENOMEM;
0143     }
0144 
0145     input_dev->name = pdev->name;
0146     input_dev->phys = "keyscan-keys/input0";
0147     input_dev->dev.parent = &pdev->dev;
0148     input_dev->open = keyscan_open;
0149     input_dev->close = keyscan_close;
0150 
0151     input_dev->id.bustype = BUS_HOST;
0152 
0153     keypad_data->input_dev = input_dev;
0154 
0155     error = keypad_matrix_key_parse_dt(keypad_data);
0156     if (error)
0157         return error;
0158 
0159     error = matrix_keypad_build_keymap(NULL, NULL,
0160                        keypad_data->n_rows,
0161                        keypad_data->n_cols,
0162                        NULL, input_dev);
0163     if (error) {
0164         dev_err(&pdev->dev, "failed to build keymap\n");
0165         return error;
0166     }
0167 
0168     input_set_drvdata(input_dev, keypad_data);
0169 
0170     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0171     keypad_data->base = devm_ioremap_resource(&pdev->dev, res);
0172     if (IS_ERR(keypad_data->base))
0173         return PTR_ERR(keypad_data->base);
0174 
0175     keypad_data->clk = devm_clk_get(&pdev->dev, NULL);
0176     if (IS_ERR(keypad_data->clk)) {
0177         dev_err(&pdev->dev, "cannot get clock\n");
0178         return PTR_ERR(keypad_data->clk);
0179     }
0180 
0181     error = clk_enable(keypad_data->clk);
0182     if (error) {
0183         dev_err(&pdev->dev, "failed to enable clock\n");
0184         return error;
0185     }
0186 
0187     keyscan_stop(keypad_data);
0188 
0189     keypad_data->irq = platform_get_irq(pdev, 0);
0190     if (keypad_data->irq < 0)
0191         return -EINVAL;
0192 
0193     error = devm_request_irq(&pdev->dev, keypad_data->irq, keyscan_isr, 0,
0194                  pdev->name, keypad_data);
0195     if (error) {
0196         dev_err(&pdev->dev, "failed to request IRQ\n");
0197         return error;
0198     }
0199 
0200     error = input_register_device(input_dev);
0201     if (error) {
0202         dev_err(&pdev->dev, "failed to register input device\n");
0203         return error;
0204     }
0205 
0206     platform_set_drvdata(pdev, keypad_data);
0207 
0208     device_set_wakeup_capable(&pdev->dev, 1);
0209 
0210     return 0;
0211 }
0212 
0213 #ifdef CONFIG_PM_SLEEP
0214 static int keyscan_suspend(struct device *dev)
0215 {
0216     struct platform_device *pdev = to_platform_device(dev);
0217     struct st_keyscan *keypad = platform_get_drvdata(pdev);
0218     struct input_dev *input = keypad->input_dev;
0219 
0220     mutex_lock(&input->mutex);
0221 
0222     if (device_may_wakeup(dev))
0223         enable_irq_wake(keypad->irq);
0224     else if (input_device_enabled(input))
0225         keyscan_stop(keypad);
0226 
0227     mutex_unlock(&input->mutex);
0228     return 0;
0229 }
0230 
0231 static int keyscan_resume(struct device *dev)
0232 {
0233     struct platform_device *pdev = to_platform_device(dev);
0234     struct st_keyscan *keypad = platform_get_drvdata(pdev);
0235     struct input_dev *input = keypad->input_dev;
0236     int retval = 0;
0237 
0238     mutex_lock(&input->mutex);
0239 
0240     if (device_may_wakeup(dev))
0241         disable_irq_wake(keypad->irq);
0242     else if (input_device_enabled(input))
0243         retval = keyscan_start(keypad);
0244 
0245     mutex_unlock(&input->mutex);
0246     return retval;
0247 }
0248 #endif
0249 
0250 static SIMPLE_DEV_PM_OPS(keyscan_dev_pm_ops, keyscan_suspend, keyscan_resume);
0251 
0252 static const struct of_device_id keyscan_of_match[] = {
0253     { .compatible = "st,sti-keyscan" },
0254     { },
0255 };
0256 MODULE_DEVICE_TABLE(of, keyscan_of_match);
0257 
0258 static struct platform_driver keyscan_device_driver = {
0259     .probe      = keyscan_probe,
0260     .driver     = {
0261         .name   = "st-keyscan",
0262         .pm = &keyscan_dev_pm_ops,
0263         .of_match_table = of_match_ptr(keyscan_of_match),
0264     }
0265 };
0266 
0267 module_platform_driver(keyscan_device_driver);
0268 
0269 MODULE_AUTHOR("Stuart Menefy <stuart.menefy@st.com>");
0270 MODULE_DESCRIPTION("STMicroelectronics keyscan device driver");
0271 MODULE_LICENSE("GPL");