root/drivers/input/keyboard/clps711x-keypad.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. clps711x_keypad_poll
  2. clps711x_keypad_probe
  3. clps711x_keypad_remove

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * Cirrus Logic CLPS711X Keypad driver
   4  *
   5  * Copyright (C) 2014 Alexander Shiyan <shc_work@mail.ru>
   6  */
   7 
   8 #include <linux/input.h>
   9 #include <linux/input-polldev.h>
  10 #include <linux/module.h>
  11 #include <linux/of_gpio.h>
  12 #include <linux/platform_device.h>
  13 #include <linux/regmap.h>
  14 #include <linux/sched.h>
  15 #include <linux/input/matrix_keypad.h>
  16 #include <linux/mfd/syscon.h>
  17 #include <linux/mfd/syscon/clps711x.h>
  18 
  19 #define CLPS711X_KEYPAD_COL_COUNT       8
  20 
  21 struct clps711x_gpio_data {
  22         struct gpio_desc *desc;
  23         DECLARE_BITMAP(last_state, CLPS711X_KEYPAD_COL_COUNT);
  24 };
  25 
  26 struct clps711x_keypad_data {
  27         struct regmap                   *syscon;
  28         int                             row_count;
  29         unsigned int                    row_shift;
  30         struct clps711x_gpio_data       *gpio_data;
  31 };
  32 
  33 static void clps711x_keypad_poll(struct input_polled_dev *dev)
  34 {
  35         const unsigned short *keycodes = dev->input->keycode;
  36         struct clps711x_keypad_data *priv = dev->private;
  37         bool sync = false;
  38         int col, row;
  39 
  40         for (col = 0; col < CLPS711X_KEYPAD_COL_COUNT; col++) {
  41                 /* Assert column */
  42                 regmap_update_bits(priv->syscon, SYSCON_OFFSET,
  43                                    SYSCON1_KBDSCAN_MASK,
  44                                    SYSCON1_KBDSCAN(8 + col));
  45 
  46                 /* Scan rows */
  47                 for (row = 0; row < priv->row_count; row++) {
  48                         struct clps711x_gpio_data *data = &priv->gpio_data[row];
  49                         bool state, state1;
  50 
  51                         /* Read twice for protection against fluctuations */
  52                         do {
  53                                 state = gpiod_get_value_cansleep(data->desc);
  54                                 cond_resched();
  55                                 state1 = gpiod_get_value_cansleep(data->desc);
  56                         } while (state != state1);
  57 
  58                         if (test_bit(col, data->last_state) != state) {
  59                                 int code = MATRIX_SCAN_CODE(row, col,
  60                                                             priv->row_shift);
  61 
  62                                 if (state) {
  63                                         set_bit(col, data->last_state);
  64                                         input_event(dev->input, EV_MSC,
  65                                                     MSC_SCAN, code);
  66                                 } else {
  67                                         clear_bit(col, data->last_state);
  68                                 }
  69 
  70                                 if (keycodes[code])
  71                                         input_report_key(dev->input,
  72                                                          keycodes[code], state);
  73                                 sync = true;
  74                         }
  75                 }
  76 
  77                 /* Set all columns to low */
  78                 regmap_update_bits(priv->syscon, SYSCON_OFFSET,
  79                                    SYSCON1_KBDSCAN_MASK, SYSCON1_KBDSCAN(1));
  80         }
  81 
  82         if (sync)
  83                 input_sync(dev->input);
  84 }
  85 
  86 static int clps711x_keypad_probe(struct platform_device *pdev)
  87 {
  88         struct clps711x_keypad_data *priv;
  89         struct device *dev = &pdev->dev;
  90         struct device_node *np = dev->of_node;
  91         struct input_polled_dev *poll_dev;
  92         u32 poll_interval;
  93         int i, err;
  94 
  95         priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
  96         if (!priv)
  97                 return -ENOMEM;
  98 
  99         priv->syscon =
 100                 syscon_regmap_lookup_by_compatible("cirrus,ep7209-syscon1");
 101         if (IS_ERR(priv->syscon))
 102                 return PTR_ERR(priv->syscon);
 103 
 104         priv->row_count = of_gpio_named_count(np, "row-gpios");
 105         if (priv->row_count < 1)
 106                 return -EINVAL;
 107 
 108         priv->gpio_data = devm_kcalloc(dev,
 109                                 priv->row_count, sizeof(*priv->gpio_data),
 110                                 GFP_KERNEL);
 111         if (!priv->gpio_data)
 112                 return -ENOMEM;
 113 
 114         priv->row_shift = get_count_order(CLPS711X_KEYPAD_COL_COUNT);
 115 
 116         for (i = 0; i < priv->row_count; i++) {
 117                 struct clps711x_gpio_data *data = &priv->gpio_data[i];
 118 
 119                 data->desc = devm_gpiod_get_index(dev, "row", i, GPIOD_IN);
 120                 if (IS_ERR(data->desc))
 121                         return PTR_ERR(data->desc);
 122         }
 123 
 124         err = of_property_read_u32(np, "poll-interval", &poll_interval);
 125         if (err)
 126                 return err;
 127 
 128         poll_dev = input_allocate_polled_device();
 129         if (!poll_dev)
 130                 return -ENOMEM;
 131 
 132         poll_dev->private               = priv;
 133         poll_dev->poll                  = clps711x_keypad_poll;
 134         poll_dev->poll_interval         = poll_interval;
 135         poll_dev->input->name           = pdev->name;
 136         poll_dev->input->dev.parent     = dev;
 137         poll_dev->input->id.bustype     = BUS_HOST;
 138         poll_dev->input->id.vendor      = 0x0001;
 139         poll_dev->input->id.product     = 0x0001;
 140         poll_dev->input->id.version     = 0x0100;
 141 
 142         err = matrix_keypad_build_keymap(NULL, NULL, priv->row_count,
 143                                          CLPS711X_KEYPAD_COL_COUNT,
 144                                          NULL, poll_dev->input);
 145         if (err)
 146                 goto out_err;
 147 
 148         input_set_capability(poll_dev->input, EV_MSC, MSC_SCAN);
 149         if (of_property_read_bool(np, "autorepeat"))
 150                 __set_bit(EV_REP, poll_dev->input->evbit);
 151 
 152         platform_set_drvdata(pdev, poll_dev);
 153 
 154         /* Set all columns to low */
 155         regmap_update_bits(priv->syscon, SYSCON_OFFSET, SYSCON1_KBDSCAN_MASK,
 156                            SYSCON1_KBDSCAN(1));
 157 
 158         err = input_register_polled_device(poll_dev);
 159         if (err)
 160                 goto out_err;
 161 
 162         return 0;
 163 
 164 out_err:
 165         input_free_polled_device(poll_dev);
 166         return err;
 167 }
 168 
 169 static int clps711x_keypad_remove(struct platform_device *pdev)
 170 {
 171         struct input_polled_dev *poll_dev = platform_get_drvdata(pdev);
 172 
 173         input_unregister_polled_device(poll_dev);
 174         input_free_polled_device(poll_dev);
 175 
 176         return 0;
 177 }
 178 
 179 static const struct of_device_id clps711x_keypad_of_match[] = {
 180         { .compatible = "cirrus,ep7209-keypad", },
 181         { }
 182 };
 183 MODULE_DEVICE_TABLE(of, clps711x_keypad_of_match);
 184 
 185 static struct platform_driver clps711x_keypad_driver = {
 186         .driver = {
 187                 .name           = "clps711x-keypad",
 188                 .of_match_table = clps711x_keypad_of_match,
 189         },
 190         .probe  = clps711x_keypad_probe,
 191         .remove = clps711x_keypad_remove,
 192 };
 193 module_platform_driver(clps711x_keypad_driver);
 194 
 195 MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>");
 196 MODULE_DESCRIPTION("Cirrus Logic CLPS711X Keypad driver");
 197 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */