Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * SPEAr Keyboard Driver
0003  * Based on omap-keypad driver
0004  *
0005  * Copyright (C) 2010 ST Microelectronics
0006  * Rajeev Kumar <rajeevkumar.linux@gmail.com>
0007  *
0008  * This file is licensed under the terms of the GNU General Public
0009  * License version 2. This program is licensed "as is" without any
0010  * warranty of any kind, whether express or implied.
0011  */
0012 
0013 #include <linux/clk.h>
0014 #include <linux/errno.h>
0015 #include <linux/interrupt.h>
0016 #include <linux/input.h>
0017 #include <linux/io.h>
0018 #include <linux/irq.h>
0019 #include <linux/kernel.h>
0020 #include <linux/module.h>
0021 #include <linux/of.h>
0022 #include <linux/platform_device.h>
0023 #include <linux/pm_wakeup.h>
0024 #include <linux/slab.h>
0025 #include <linux/types.h>
0026 #include <linux/platform_data/keyboard-spear.h>
0027 
0028 /* Keyboard Registers */
0029 #define MODE_CTL_REG    0x00
0030 #define STATUS_REG  0x0C
0031 #define DATA_REG    0x10
0032 #define INTR_MASK   0x54
0033 
0034 /* Register Values */
0035 #define NUM_ROWS    16
0036 #define NUM_COLS    16
0037 #define MODE_CTL_PCLK_FREQ_SHIFT    9
0038 #define MODE_CTL_PCLK_FREQ_MSK      0x7F
0039 
0040 #define MODE_CTL_KEYBOARD   (0x2 << 0)
0041 #define MODE_CTL_SCAN_RATE_10   (0x0 << 2)
0042 #define MODE_CTL_SCAN_RATE_20   (0x1 << 2)
0043 #define MODE_CTL_SCAN_RATE_40   (0x2 << 2)
0044 #define MODE_CTL_SCAN_RATE_80   (0x3 << 2)
0045 #define MODE_CTL_KEYNUM_SHIFT   6
0046 #define MODE_CTL_START_SCAN (0x1 << 8)
0047 
0048 #define STATUS_DATA_AVAIL   (0x1 << 1)
0049 
0050 #define DATA_ROW_MASK       0xF0
0051 #define DATA_COLUMN_MASK    0x0F
0052 
0053 #define ROW_SHIFT       4
0054 
0055 struct spear_kbd {
0056     struct input_dev *input;
0057     void __iomem *io_base;
0058     struct clk *clk;
0059     unsigned int irq;
0060     unsigned int mode;
0061     unsigned int suspended_rate;
0062     unsigned short last_key;
0063     unsigned short keycodes[NUM_ROWS * NUM_COLS];
0064     bool rep;
0065     bool irq_wake_enabled;
0066     u32 mode_ctl_reg;
0067 };
0068 
0069 static irqreturn_t spear_kbd_interrupt(int irq, void *dev_id)
0070 {
0071     struct spear_kbd *kbd = dev_id;
0072     struct input_dev *input = kbd->input;
0073     unsigned int key;
0074     u32 sts, val;
0075 
0076     sts = readl_relaxed(kbd->io_base + STATUS_REG);
0077     if (!(sts & STATUS_DATA_AVAIL))
0078         return IRQ_NONE;
0079 
0080     if (kbd->last_key != KEY_RESERVED) {
0081         input_report_key(input, kbd->last_key, 0);
0082         kbd->last_key = KEY_RESERVED;
0083     }
0084 
0085     /* following reads active (row, col) pair */
0086     val = readl_relaxed(kbd->io_base + DATA_REG) &
0087         (DATA_ROW_MASK | DATA_COLUMN_MASK);
0088     key = kbd->keycodes[val];
0089 
0090     input_event(input, EV_MSC, MSC_SCAN, val);
0091     input_report_key(input, key, 1);
0092     input_sync(input);
0093 
0094     kbd->last_key = key;
0095 
0096     /* clear interrupt */
0097     writel_relaxed(0, kbd->io_base + STATUS_REG);
0098 
0099     return IRQ_HANDLED;
0100 }
0101 
0102 static int spear_kbd_open(struct input_dev *dev)
0103 {
0104     struct spear_kbd *kbd = input_get_drvdata(dev);
0105     int error;
0106     u32 val;
0107 
0108     kbd->last_key = KEY_RESERVED;
0109 
0110     error = clk_enable(kbd->clk);
0111     if (error)
0112         return error;
0113 
0114     /* keyboard rate to be programmed is input clock (in MHz) - 1 */
0115     val = clk_get_rate(kbd->clk) / 1000000 - 1;
0116     val = (val & MODE_CTL_PCLK_FREQ_MSK) << MODE_CTL_PCLK_FREQ_SHIFT;
0117 
0118     /* program keyboard */
0119     val = MODE_CTL_SCAN_RATE_80 | MODE_CTL_KEYBOARD | val |
0120         (kbd->mode << MODE_CTL_KEYNUM_SHIFT);
0121     writel_relaxed(val, kbd->io_base + MODE_CTL_REG);
0122     writel_relaxed(1, kbd->io_base + STATUS_REG);
0123 
0124     /* start key scan */
0125     val = readl_relaxed(kbd->io_base + MODE_CTL_REG);
0126     val |= MODE_CTL_START_SCAN;
0127     writel_relaxed(val, kbd->io_base + MODE_CTL_REG);
0128 
0129     return 0;
0130 }
0131 
0132 static void spear_kbd_close(struct input_dev *dev)
0133 {
0134     struct spear_kbd *kbd = input_get_drvdata(dev);
0135     u32 val;
0136 
0137     /* stop key scan */
0138     val = readl_relaxed(kbd->io_base + MODE_CTL_REG);
0139     val &= ~MODE_CTL_START_SCAN;
0140     writel_relaxed(val, kbd->io_base + MODE_CTL_REG);
0141 
0142     clk_disable(kbd->clk);
0143 
0144     kbd->last_key = KEY_RESERVED;
0145 }
0146 
0147 #ifdef CONFIG_OF
0148 static int spear_kbd_parse_dt(struct platform_device *pdev,
0149                                         struct spear_kbd *kbd)
0150 {
0151     struct device_node *np = pdev->dev.of_node;
0152     int error;
0153     u32 val, suspended_rate;
0154 
0155     if (!np) {
0156         dev_err(&pdev->dev, "Missing DT data\n");
0157         return -EINVAL;
0158     }
0159 
0160     if (of_property_read_bool(np, "autorepeat"))
0161         kbd->rep = true;
0162 
0163     if (of_property_read_u32(np, "suspended_rate", &suspended_rate))
0164         kbd->suspended_rate = suspended_rate;
0165 
0166     error = of_property_read_u32(np, "st,mode", &val);
0167     if (error) {
0168         dev_err(&pdev->dev, "DT: Invalid or missing mode\n");
0169         return error;
0170     }
0171 
0172     kbd->mode = val;
0173     return 0;
0174 }
0175 #else
0176 static inline int spear_kbd_parse_dt(struct platform_device *pdev,
0177                      struct spear_kbd *kbd)
0178 {
0179     return -ENOSYS;
0180 }
0181 #endif
0182 
0183 static int spear_kbd_probe(struct platform_device *pdev)
0184 {
0185     struct kbd_platform_data *pdata = dev_get_platdata(&pdev->dev);
0186     const struct matrix_keymap_data *keymap = pdata ? pdata->keymap : NULL;
0187     struct spear_kbd *kbd;
0188     struct input_dev *input_dev;
0189     struct resource *res;
0190     int irq;
0191     int error;
0192 
0193     irq = platform_get_irq(pdev, 0);
0194     if (irq < 0)
0195         return irq;
0196 
0197     kbd = devm_kzalloc(&pdev->dev, sizeof(*kbd), GFP_KERNEL);
0198     if (!kbd) {
0199         dev_err(&pdev->dev, "not enough memory for driver data\n");
0200         return -ENOMEM;
0201     }
0202 
0203     input_dev = devm_input_allocate_device(&pdev->dev);
0204     if (!input_dev) {
0205         dev_err(&pdev->dev, "unable to allocate input device\n");
0206         return -ENOMEM;
0207     }
0208 
0209     kbd->input = input_dev;
0210     kbd->irq = irq;
0211 
0212     if (!pdata) {
0213         error = spear_kbd_parse_dt(pdev, kbd);
0214         if (error)
0215             return error;
0216     } else {
0217         kbd->mode = pdata->mode;
0218         kbd->rep = pdata->rep;
0219         kbd->suspended_rate = pdata->suspended_rate;
0220     }
0221 
0222     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0223     kbd->io_base = devm_ioremap_resource(&pdev->dev, res);
0224     if (IS_ERR(kbd->io_base))
0225         return PTR_ERR(kbd->io_base);
0226 
0227     kbd->clk = devm_clk_get(&pdev->dev, NULL);
0228     if (IS_ERR(kbd->clk))
0229         return PTR_ERR(kbd->clk);
0230 
0231     input_dev->name = "Spear Keyboard";
0232     input_dev->phys = "keyboard/input0";
0233     input_dev->id.bustype = BUS_HOST;
0234     input_dev->id.vendor = 0x0001;
0235     input_dev->id.product = 0x0001;
0236     input_dev->id.version = 0x0100;
0237     input_dev->open = spear_kbd_open;
0238     input_dev->close = spear_kbd_close;
0239 
0240     error = matrix_keypad_build_keymap(keymap, NULL, NUM_ROWS, NUM_COLS,
0241                        kbd->keycodes, input_dev);
0242     if (error) {
0243         dev_err(&pdev->dev, "Failed to build keymap\n");
0244         return error;
0245     }
0246 
0247     if (kbd->rep)
0248         __set_bit(EV_REP, input_dev->evbit);
0249     input_set_capability(input_dev, EV_MSC, MSC_SCAN);
0250 
0251     input_set_drvdata(input_dev, kbd);
0252 
0253     error = devm_request_irq(&pdev->dev, irq, spear_kbd_interrupt, 0,
0254             "keyboard", kbd);
0255     if (error) {
0256         dev_err(&pdev->dev, "request_irq failed\n");
0257         return error;
0258     }
0259 
0260     error = clk_prepare(kbd->clk);
0261     if (error)
0262         return error;
0263 
0264     error = input_register_device(input_dev);
0265     if (error) {
0266         dev_err(&pdev->dev, "Unable to register keyboard device\n");
0267         clk_unprepare(kbd->clk);
0268         return error;
0269     }
0270 
0271     device_init_wakeup(&pdev->dev, 1);
0272     platform_set_drvdata(pdev, kbd);
0273 
0274     return 0;
0275 }
0276 
0277 static int spear_kbd_remove(struct platform_device *pdev)
0278 {
0279     struct spear_kbd *kbd = platform_get_drvdata(pdev);
0280 
0281     input_unregister_device(kbd->input);
0282     clk_unprepare(kbd->clk);
0283 
0284     return 0;
0285 }
0286 
0287 static int __maybe_unused spear_kbd_suspend(struct device *dev)
0288 {
0289     struct platform_device *pdev = to_platform_device(dev);
0290     struct spear_kbd *kbd = platform_get_drvdata(pdev);
0291     struct input_dev *input_dev = kbd->input;
0292     unsigned int rate = 0, mode_ctl_reg, val;
0293 
0294     mutex_lock(&input_dev->mutex);
0295 
0296     /* explicitly enable clock as we may program device */
0297     clk_enable(kbd->clk);
0298 
0299     mode_ctl_reg = readl_relaxed(kbd->io_base + MODE_CTL_REG);
0300 
0301     if (device_may_wakeup(&pdev->dev)) {
0302         if (!enable_irq_wake(kbd->irq))
0303             kbd->irq_wake_enabled = true;
0304 
0305         /*
0306          * reprogram the keyboard operating frequency as on some
0307          * platform it may change during system suspended
0308          */
0309         if (kbd->suspended_rate)
0310             rate = kbd->suspended_rate / 1000000 - 1;
0311         else
0312             rate = clk_get_rate(kbd->clk) / 1000000 - 1;
0313 
0314         val = mode_ctl_reg &
0315             ~(MODE_CTL_PCLK_FREQ_MSK << MODE_CTL_PCLK_FREQ_SHIFT);
0316         val |= (rate & MODE_CTL_PCLK_FREQ_MSK)
0317             << MODE_CTL_PCLK_FREQ_SHIFT;
0318         writel_relaxed(val, kbd->io_base + MODE_CTL_REG);
0319 
0320     } else {
0321         if (input_device_enabled(input_dev)) {
0322             writel_relaxed(mode_ctl_reg & ~MODE_CTL_START_SCAN,
0323                     kbd->io_base + MODE_CTL_REG);
0324             clk_disable(kbd->clk);
0325         }
0326     }
0327 
0328     /* store current configuration */
0329     if (input_device_enabled(input_dev))
0330         kbd->mode_ctl_reg = mode_ctl_reg;
0331 
0332     /* restore previous clk state */
0333     clk_disable(kbd->clk);
0334 
0335     mutex_unlock(&input_dev->mutex);
0336 
0337     return 0;
0338 }
0339 
0340 static int __maybe_unused spear_kbd_resume(struct device *dev)
0341 {
0342     struct platform_device *pdev = to_platform_device(dev);
0343     struct spear_kbd *kbd = platform_get_drvdata(pdev);
0344     struct input_dev *input_dev = kbd->input;
0345 
0346     mutex_lock(&input_dev->mutex);
0347 
0348     if (device_may_wakeup(&pdev->dev)) {
0349         if (kbd->irq_wake_enabled) {
0350             kbd->irq_wake_enabled = false;
0351             disable_irq_wake(kbd->irq);
0352         }
0353     } else {
0354         if (input_device_enabled(input_dev))
0355             clk_enable(kbd->clk);
0356     }
0357 
0358     /* restore current configuration */
0359     if (input_device_enabled(input_dev))
0360         writel_relaxed(kbd->mode_ctl_reg, kbd->io_base + MODE_CTL_REG);
0361 
0362     mutex_unlock(&input_dev->mutex);
0363 
0364     return 0;
0365 }
0366 
0367 static SIMPLE_DEV_PM_OPS(spear_kbd_pm_ops, spear_kbd_suspend, spear_kbd_resume);
0368 
0369 #ifdef CONFIG_OF
0370 static const struct of_device_id spear_kbd_id_table[] = {
0371     { .compatible = "st,spear300-kbd" },
0372     {}
0373 };
0374 MODULE_DEVICE_TABLE(of, spear_kbd_id_table);
0375 #endif
0376 
0377 static struct platform_driver spear_kbd_driver = {
0378     .probe      = spear_kbd_probe,
0379     .remove     = spear_kbd_remove,
0380     .driver     = {
0381         .name   = "keyboard",
0382         .pm = &spear_kbd_pm_ops,
0383         .of_match_table = of_match_ptr(spear_kbd_id_table),
0384     },
0385 };
0386 module_platform_driver(spear_kbd_driver);
0387 
0388 MODULE_AUTHOR("Rajeev Kumar");
0389 MODULE_DESCRIPTION("SPEAr Keyboard Driver");
0390 MODULE_LICENSE("GPL");