Path: blob/master/drivers/input/keyboard/spear-keyboard.c
15109 views
/*1* SPEAr Keyboard Driver2* Based on omap-keypad driver3*4* Copyright (C) 2010 ST Microelectronics5* Rajeev Kumar<[email protected]>6*7* This file is licensed under the terms of the GNU General Public8* License version 2. This program is licensed "as is" without any9* warranty of any kind, whether express or implied.10*/1112#include <linux/clk.h>13#include <linux/errno.h>14#include <linux/init.h>15#include <linux/interrupt.h>16#include <linux/input.h>17#include <linux/io.h>18#include <linux/irq.h>19#include <linux/kernel.h>20#include <linux/module.h>21#include <linux/platform_device.h>22#include <linux/pm_wakeup.h>23#include <linux/slab.h>24#include <linux/types.h>25#include <plat/keyboard.h>2627/* Keyboard Registers */28#define MODE_REG 0x00 /* 16 bit reg */29#define STATUS_REG 0x0C /* 2 bit reg */30#define DATA_REG 0x10 /* 8 bit reg */31#define INTR_MASK 0x543233/* Register Values */34/*35* pclk freq mask = (APB FEQ -1)= 82 MHZ.Programme bit 15-9 in mode36* control register as 1010010(82MHZ)37*/38#define PCLK_FREQ_MSK 0xA400 /* 82 MHz */39#define START_SCAN 0x010040#define SCAN_RATE_10 0x000041#define SCAN_RATE_20 0x000442#define SCAN_RATE_40 0x000843#define SCAN_RATE_80 0x000C44#define MODE_KEYBOARD 0x000245#define DATA_AVAIL 0x24647#define KEY_MASK 0xFF00000048#define KEY_VALUE 0x00FFFFFF49#define ROW_MASK 0xF050#define COLUMN_MASK 0x0F51#define ROW_SHIFT 45253struct spear_kbd {54struct input_dev *input;55struct resource *res;56void __iomem *io_base;57struct clk *clk;58unsigned int irq;59unsigned short last_key;60unsigned short keycodes[256];61};6263static irqreturn_t spear_kbd_interrupt(int irq, void *dev_id)64{65struct spear_kbd *kbd = dev_id;66struct input_dev *input = kbd->input;67unsigned int key;68u8 sts, val;6970sts = readb(kbd->io_base + STATUS_REG);71if (!(sts & DATA_AVAIL))72return IRQ_NONE;7374if (kbd->last_key != KEY_RESERVED) {75input_report_key(input, kbd->last_key, 0);76kbd->last_key = KEY_RESERVED;77}7879/* following reads active (row, col) pair */80val = readb(kbd->io_base + DATA_REG);81key = kbd->keycodes[val];8283input_event(input, EV_MSC, MSC_SCAN, val);84input_report_key(input, key, 1);85input_sync(input);8687kbd->last_key = key;8889/* clear interrupt */90writeb(0, kbd->io_base + STATUS_REG);9192return IRQ_HANDLED;93}9495static int spear_kbd_open(struct input_dev *dev)96{97struct spear_kbd *kbd = input_get_drvdata(dev);98int error;99u16 val;100101kbd->last_key = KEY_RESERVED;102103error = clk_enable(kbd->clk);104if (error)105return error;106107/* program keyboard */108val = SCAN_RATE_80 | MODE_KEYBOARD | PCLK_FREQ_MSK;109writew(val, kbd->io_base + MODE_REG);110writeb(1, kbd->io_base + STATUS_REG);111112/* start key scan */113val = readw(kbd->io_base + MODE_REG);114val |= START_SCAN;115writew(val, kbd->io_base + MODE_REG);116117return 0;118}119120static void spear_kbd_close(struct input_dev *dev)121{122struct spear_kbd *kbd = input_get_drvdata(dev);123u16 val;124125/* stop key scan */126val = readw(kbd->io_base + MODE_REG);127val &= ~START_SCAN;128writew(val, kbd->io_base + MODE_REG);129130clk_disable(kbd->clk);131132kbd->last_key = KEY_RESERVED;133}134135static int __devinit spear_kbd_probe(struct platform_device *pdev)136{137const struct kbd_platform_data *pdata = pdev->dev.platform_data;138const struct matrix_keymap_data *keymap;139struct spear_kbd *kbd;140struct input_dev *input_dev;141struct resource *res;142int irq;143int error;144145if (!pdata) {146dev_err(&pdev->dev, "Invalid platform data\n");147return -EINVAL;148}149150keymap = pdata->keymap;151if (!keymap) {152dev_err(&pdev->dev, "no keymap defined\n");153return -EINVAL;154}155156res = platform_get_resource(pdev, IORESOURCE_MEM, 0);157if (!res) {158dev_err(&pdev->dev, "no keyboard resource defined\n");159return -EBUSY;160}161162irq = platform_get_irq(pdev, 0);163if (irq < 0) {164dev_err(&pdev->dev, "not able to get irq for the device\n");165return irq;166}167168kbd = kzalloc(sizeof(*kbd), GFP_KERNEL);169input_dev = input_allocate_device();170if (!kbd || !input_dev) {171dev_err(&pdev->dev, "out of memory\n");172error = -ENOMEM;173goto err_free_mem;174}175176kbd->input = input_dev;177kbd->irq = irq;178kbd->res = request_mem_region(res->start, resource_size(res),179pdev->name);180if (!kbd->res) {181dev_err(&pdev->dev, "keyboard region already claimed\n");182error = -EBUSY;183goto err_free_mem;184}185186kbd->io_base = ioremap(res->start, resource_size(res));187if (!kbd->io_base) {188dev_err(&pdev->dev, "ioremap failed for kbd_region\n");189error = -ENOMEM;190goto err_release_mem_region;191}192193kbd->clk = clk_get(&pdev->dev, NULL);194if (IS_ERR(kbd->clk)) {195error = PTR_ERR(kbd->clk);196goto err_iounmap;197}198199input_dev->name = "Spear Keyboard";200input_dev->phys = "keyboard/input0";201input_dev->dev.parent = &pdev->dev;202input_dev->id.bustype = BUS_HOST;203input_dev->id.vendor = 0x0001;204input_dev->id.product = 0x0001;205input_dev->id.version = 0x0100;206input_dev->open = spear_kbd_open;207input_dev->close = spear_kbd_close;208209__set_bit(EV_KEY, input_dev->evbit);210if (pdata->rep)211__set_bit(EV_REP, input_dev->evbit);212input_set_capability(input_dev, EV_MSC, MSC_SCAN);213214input_dev->keycode = kbd->keycodes;215input_dev->keycodesize = sizeof(kbd->keycodes[0]);216input_dev->keycodemax = ARRAY_SIZE(kbd->keycodes);217218matrix_keypad_build_keymap(keymap, ROW_SHIFT,219input_dev->keycode, input_dev->keybit);220221input_set_drvdata(input_dev, kbd);222223error = request_irq(irq, spear_kbd_interrupt, 0, "keyboard", kbd);224if (error) {225dev_err(&pdev->dev, "request_irq fail\n");226goto err_put_clk;227}228229error = input_register_device(input_dev);230if (error) {231dev_err(&pdev->dev, "Unable to register keyboard device\n");232goto err_free_irq;233}234235device_init_wakeup(&pdev->dev, 1);236platform_set_drvdata(pdev, kbd);237238return 0;239240err_free_irq:241free_irq(kbd->irq, kbd);242err_put_clk:243clk_put(kbd->clk);244err_iounmap:245iounmap(kbd->io_base);246err_release_mem_region:247release_mem_region(res->start, resource_size(res));248err_free_mem:249input_free_device(input_dev);250kfree(kbd);251252return error;253}254255static int __devexit spear_kbd_remove(struct platform_device *pdev)256{257struct spear_kbd *kbd = platform_get_drvdata(pdev);258259free_irq(kbd->irq, kbd);260input_unregister_device(kbd->input);261clk_put(kbd->clk);262iounmap(kbd->io_base);263release_mem_region(kbd->res->start, resource_size(kbd->res));264kfree(kbd);265266device_init_wakeup(&pdev->dev, 1);267platform_set_drvdata(pdev, NULL);268269return 0;270}271272#ifdef CONFIG_PM273static int spear_kbd_suspend(struct device *dev)274{275struct platform_device *pdev = to_platform_device(dev);276struct spear_kbd *kbd = platform_get_drvdata(pdev);277struct input_dev *input_dev = kbd->input;278279mutex_lock(&input_dev->mutex);280281if (input_dev->users)282clk_enable(kbd->clk);283284if (device_may_wakeup(&pdev->dev))285enable_irq_wake(kbd->irq);286287mutex_unlock(&input_dev->mutex);288289return 0;290}291292static int spear_kbd_resume(struct device *dev)293{294struct platform_device *pdev = to_platform_device(dev);295struct spear_kbd *kbd = platform_get_drvdata(pdev);296struct input_dev *input_dev = kbd->input;297298mutex_lock(&input_dev->mutex);299300if (device_may_wakeup(&pdev->dev))301disable_irq_wake(kbd->irq);302303if (input_dev->users)304clk_enable(kbd->clk);305306mutex_unlock(&input_dev->mutex);307308return 0;309}310311static const struct dev_pm_ops spear_kbd_pm_ops = {312.suspend = spear_kbd_suspend,313.resume = spear_kbd_resume,314};315#endif316317static struct platform_driver spear_kbd_driver = {318.probe = spear_kbd_probe,319.remove = __devexit_p(spear_kbd_remove),320.driver = {321.name = "keyboard",322.owner = THIS_MODULE,323#ifdef CONFIG_PM324.pm = &spear_kbd_pm_ops,325#endif326},327};328329static int __init spear_kbd_init(void)330{331return platform_driver_register(&spear_kbd_driver);332}333module_init(spear_kbd_init);334335static void __exit spear_kbd_exit(void)336{337platform_driver_unregister(&spear_kbd_driver);338}339module_exit(spear_kbd_exit);340341MODULE_AUTHOR("Rajeev Kumar");342MODULE_DESCRIPTION("SPEAr Keyboard Driver");343MODULE_LICENSE("GPL");344345346