root/drivers/input/keyboard/sun4i-lradc-keys.c

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

DEFINITIONS

This source file includes following definitions.
  1. sun4i_lradc_irq
  2. sun4i_lradc_open
  3. sun4i_lradc_close
  4. sun4i_lradc_load_dt_keymap
  5. sun4i_lradc_probe

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * Allwinner sun4i low res adc attached tablet keys driver
   4  *
   5  * Copyright (C) 2014 Hans de Goede <hdegoede@redhat.com>
   6  */
   7 
   8 /*
   9  * Allwinnner sunxi SoCs have a lradc which is specifically designed to have
  10  * various (tablet) keys (ie home, back, search, etc). attached to it using
  11  * a resistor network. This driver is for the keys on such boards.
  12  *
  13  * There are 2 channels, currently this driver only supports channel 0 since
  14  * there are no boards known to use channel 1.
  15  */
  16 
  17 #include <linux/err.h>
  18 #include <linux/init.h>
  19 #include <linux/input.h>
  20 #include <linux/interrupt.h>
  21 #include <linux/io.h>
  22 #include <linux/module.h>
  23 #include <linux/of_platform.h>
  24 #include <linux/platform_device.h>
  25 #include <linux/regulator/consumer.h>
  26 #include <linux/slab.h>
  27 
  28 #define LRADC_CTRL              0x00
  29 #define LRADC_INTC              0x04
  30 #define LRADC_INTS              0x08
  31 #define LRADC_DATA0             0x0c
  32 #define LRADC_DATA1             0x10
  33 
  34 /* LRADC_CTRL bits */
  35 #define FIRST_CONVERT_DLY(x)    ((x) << 24) /* 8 bits */
  36 #define CHAN_SELECT(x)          ((x) << 22) /* 2 bits */
  37 #define CONTINUE_TIME_SEL(x)    ((x) << 16) /* 4 bits */
  38 #define KEY_MODE_SEL(x)         ((x) << 12) /* 2 bits */
  39 #define LEVELA_B_CNT(x)         ((x) << 8)  /* 4 bits */
  40 #define HOLD_KEY_EN(x)          ((x) << 7)
  41 #define HOLD_EN(x)              ((x) << 6)
  42 #define LEVELB_VOL(x)           ((x) << 4)  /* 2 bits */
  43 #define SAMPLE_RATE(x)          ((x) << 2)  /* 2 bits */
  44 #define ENABLE(x)               ((x) << 0)
  45 
  46 /* LRADC_INTC and LRADC_INTS bits */
  47 #define CHAN1_KEYUP_IRQ         BIT(12)
  48 #define CHAN1_ALRDY_HOLD_IRQ    BIT(11)
  49 #define CHAN1_HOLD_IRQ          BIT(10)
  50 #define CHAN1_KEYDOWN_IRQ       BIT(9)
  51 #define CHAN1_DATA_IRQ          BIT(8)
  52 #define CHAN0_KEYUP_IRQ         BIT(4)
  53 #define CHAN0_ALRDY_HOLD_IRQ    BIT(3)
  54 #define CHAN0_HOLD_IRQ          BIT(2)
  55 #define CHAN0_KEYDOWN_IRQ       BIT(1)
  56 #define CHAN0_DATA_IRQ          BIT(0)
  57 
  58 /* struct lradc_variant - Describe sun4i-a10-lradc-keys hardware variant
  59  * @divisor_numerator:          The numerator of lradc Vref internally divisor
  60  * @divisor_denominator:        The denominator of lradc Vref internally divisor
  61  */
  62 struct lradc_variant {
  63         u8 divisor_numerator;
  64         u8 divisor_denominator;
  65 };
  66 
  67 static const struct lradc_variant lradc_variant_a10 = {
  68         .divisor_numerator = 2,
  69         .divisor_denominator = 3
  70 };
  71 
  72 static const struct lradc_variant r_lradc_variant_a83t = {
  73         .divisor_numerator = 3,
  74         .divisor_denominator = 4
  75 };
  76 
  77 struct sun4i_lradc_keymap {
  78         u32 voltage;
  79         u32 keycode;
  80 };
  81 
  82 struct sun4i_lradc_data {
  83         struct device *dev;
  84         struct input_dev *input;
  85         void __iomem *base;
  86         struct regulator *vref_supply;
  87         struct sun4i_lradc_keymap *chan0_map;
  88         const struct lradc_variant *variant;
  89         u32 chan0_map_count;
  90         u32 chan0_keycode;
  91         u32 vref;
  92 };
  93 
  94 static irqreturn_t sun4i_lradc_irq(int irq, void *dev_id)
  95 {
  96         struct sun4i_lradc_data *lradc = dev_id;
  97         u32 i, ints, val, voltage, diff, keycode = 0, closest = 0xffffffff;
  98 
  99         ints  = readl(lradc->base + LRADC_INTS);
 100 
 101         /*
 102          * lradc supports only one keypress at a time, release does not give
 103          * any info as to which key was released, so we cache the keycode.
 104          */
 105 
 106         if (ints & CHAN0_KEYUP_IRQ) {
 107                 input_report_key(lradc->input, lradc->chan0_keycode, 0);
 108                 lradc->chan0_keycode = 0;
 109         }
 110 
 111         if ((ints & CHAN0_KEYDOWN_IRQ) && lradc->chan0_keycode == 0) {
 112                 val = readl(lradc->base + LRADC_DATA0) & 0x3f;
 113                 voltage = val * lradc->vref / 63;
 114 
 115                 for (i = 0; i < lradc->chan0_map_count; i++) {
 116                         diff = abs(lradc->chan0_map[i].voltage - voltage);
 117                         if (diff < closest) {
 118                                 closest = diff;
 119                                 keycode = lradc->chan0_map[i].keycode;
 120                         }
 121                 }
 122 
 123                 lradc->chan0_keycode = keycode;
 124                 input_report_key(lradc->input, lradc->chan0_keycode, 1);
 125         }
 126 
 127         input_sync(lradc->input);
 128 
 129         writel(ints, lradc->base + LRADC_INTS);
 130 
 131         return IRQ_HANDLED;
 132 }
 133 
 134 static int sun4i_lradc_open(struct input_dev *dev)
 135 {
 136         struct sun4i_lradc_data *lradc = input_get_drvdata(dev);
 137         int error;
 138 
 139         error = regulator_enable(lradc->vref_supply);
 140         if (error)
 141                 return error;
 142 
 143         lradc->vref = regulator_get_voltage(lradc->vref_supply) *
 144                       lradc->variant->divisor_numerator /
 145                       lradc->variant->divisor_denominator;
 146         /*
 147          * Set sample time to 4 ms / 250 Hz. Wait 2 * 4 ms for key to
 148          * stabilize on press, wait (1 + 1) * 4 ms for key release
 149          */
 150         writel(FIRST_CONVERT_DLY(2) | LEVELA_B_CNT(1) | HOLD_EN(1) |
 151                 SAMPLE_RATE(0) | ENABLE(1), lradc->base + LRADC_CTRL);
 152 
 153         writel(CHAN0_KEYUP_IRQ | CHAN0_KEYDOWN_IRQ, lradc->base + LRADC_INTC);
 154 
 155         return 0;
 156 }
 157 
 158 static void sun4i_lradc_close(struct input_dev *dev)
 159 {
 160         struct sun4i_lradc_data *lradc = input_get_drvdata(dev);
 161 
 162         /* Disable lradc, leave other settings unchanged */
 163         writel(FIRST_CONVERT_DLY(2) | LEVELA_B_CNT(1) | HOLD_EN(1) |
 164                 SAMPLE_RATE(2), lradc->base + LRADC_CTRL);
 165         writel(0, lradc->base + LRADC_INTC);
 166 
 167         regulator_disable(lradc->vref_supply);
 168 }
 169 
 170 static int sun4i_lradc_load_dt_keymap(struct device *dev,
 171                                       struct sun4i_lradc_data *lradc)
 172 {
 173         struct device_node *np, *pp;
 174         int i;
 175         int error;
 176 
 177         np = dev->of_node;
 178         if (!np)
 179                 return -EINVAL;
 180 
 181         lradc->chan0_map_count = of_get_child_count(np);
 182         if (lradc->chan0_map_count == 0) {
 183                 dev_err(dev, "keymap is missing in device tree\n");
 184                 return -EINVAL;
 185         }
 186 
 187         lradc->chan0_map = devm_kmalloc_array(dev, lradc->chan0_map_count,
 188                                               sizeof(struct sun4i_lradc_keymap),
 189                                               GFP_KERNEL);
 190         if (!lradc->chan0_map)
 191                 return -ENOMEM;
 192 
 193         i = 0;
 194         for_each_child_of_node(np, pp) {
 195                 struct sun4i_lradc_keymap *map = &lradc->chan0_map[i];
 196                 u32 channel;
 197 
 198                 error = of_property_read_u32(pp, "channel", &channel);
 199                 if (error || channel != 0) {
 200                         dev_err(dev, "%pOFn: Inval channel prop\n", pp);
 201                         of_node_put(pp);
 202                         return -EINVAL;
 203                 }
 204 
 205                 error = of_property_read_u32(pp, "voltage", &map->voltage);
 206                 if (error) {
 207                         dev_err(dev, "%pOFn: Inval voltage prop\n", pp);
 208                         of_node_put(pp);
 209                         return -EINVAL;
 210                 }
 211 
 212                 error = of_property_read_u32(pp, "linux,code", &map->keycode);
 213                 if (error) {
 214                         dev_err(dev, "%pOFn: Inval linux,code prop\n", pp);
 215                         of_node_put(pp);
 216                         return -EINVAL;
 217                 }
 218 
 219                 i++;
 220         }
 221 
 222         return 0;
 223 }
 224 
 225 static int sun4i_lradc_probe(struct platform_device *pdev)
 226 {
 227         struct sun4i_lradc_data *lradc;
 228         struct device *dev = &pdev->dev;
 229         int i;
 230         int error;
 231 
 232         lradc = devm_kzalloc(dev, sizeof(struct sun4i_lradc_data), GFP_KERNEL);
 233         if (!lradc)
 234                 return -ENOMEM;
 235 
 236         error = sun4i_lradc_load_dt_keymap(dev, lradc);
 237         if (error)
 238                 return error;
 239 
 240         lradc->variant = of_device_get_match_data(&pdev->dev);
 241         if (!lradc->variant) {
 242                 dev_err(&pdev->dev, "Missing sun4i-a10-lradc-keys variant\n");
 243                 return -EINVAL;
 244         }
 245 
 246         lradc->vref_supply = devm_regulator_get(dev, "vref");
 247         if (IS_ERR(lradc->vref_supply))
 248                 return PTR_ERR(lradc->vref_supply);
 249 
 250         lradc->dev = dev;
 251         lradc->input = devm_input_allocate_device(dev);
 252         if (!lradc->input)
 253                 return -ENOMEM;
 254 
 255         lradc->input->name = pdev->name;
 256         lradc->input->phys = "sun4i_lradc/input0";
 257         lradc->input->open = sun4i_lradc_open;
 258         lradc->input->close = sun4i_lradc_close;
 259         lradc->input->id.bustype = BUS_HOST;
 260         lradc->input->id.vendor = 0x0001;
 261         lradc->input->id.product = 0x0001;
 262         lradc->input->id.version = 0x0100;
 263 
 264         __set_bit(EV_KEY, lradc->input->evbit);
 265         for (i = 0; i < lradc->chan0_map_count; i++)
 266                 __set_bit(lradc->chan0_map[i].keycode, lradc->input->keybit);
 267 
 268         input_set_drvdata(lradc->input, lradc);
 269 
 270         lradc->base = devm_ioremap_resource(dev,
 271                               platform_get_resource(pdev, IORESOURCE_MEM, 0));
 272         if (IS_ERR(lradc->base))
 273                 return PTR_ERR(lradc->base);
 274 
 275         error = devm_request_irq(dev, platform_get_irq(pdev, 0),
 276                                  sun4i_lradc_irq, 0,
 277                                  "sun4i-a10-lradc-keys", lradc);
 278         if (error)
 279                 return error;
 280 
 281         error = input_register_device(lradc->input);
 282         if (error)
 283                 return error;
 284 
 285         return 0;
 286 }
 287 
 288 static const struct of_device_id sun4i_lradc_of_match[] = {
 289         { .compatible = "allwinner,sun4i-a10-lradc-keys",
 290                 .data = &lradc_variant_a10 },
 291         { .compatible = "allwinner,sun8i-a83t-r-lradc",
 292                 .data = &r_lradc_variant_a83t },
 293         { /* sentinel */ }
 294 };
 295 MODULE_DEVICE_TABLE(of, sun4i_lradc_of_match);
 296 
 297 static struct platform_driver sun4i_lradc_driver = {
 298         .driver = {
 299                 .name   = "sun4i-a10-lradc-keys",
 300                 .of_match_table = of_match_ptr(sun4i_lradc_of_match),
 301         },
 302         .probe  = sun4i_lradc_probe,
 303 };
 304 
 305 module_platform_driver(sun4i_lradc_driver);
 306 
 307 MODULE_DESCRIPTION("Allwinner sun4i low res adc attached tablet keys driver");
 308 MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
 309 MODULE_LICENSE("GPL");

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