Path: blob/master/drivers/input/misc/dm355evm_keys.c
15109 views
/*1* dm355evm_keys.c - support buttons and IR remote on DM355 EVM board2*3* Copyright (c) 2008 by David Brownell4*5* This program is free software; you can redistribute it and/or6* modify it under the terms of the GNU General Public License7* as published by the Free Software Foundation; either version8* 2 of the License, or (at your option) any later version.9*/10#include <linux/kernel.h>11#include <linux/init.h>12#include <linux/slab.h>13#include <linux/input.h>14#include <linux/input/sparse-keymap.h>15#include <linux/platform_device.h>16#include <linux/interrupt.h>1718#include <linux/i2c/dm355evm_msp.h>192021/*22* The MSP430 firmware on the DM355 EVM monitors on-board pushbuttons23* and an IR receptor used for the remote control. When any key is24* pressed, or its autorepeat kicks in, an event is sent. This driver25* read those events from the small (32 event) queue and reports them.26*27* Note that physically there can only be one of these devices.28*29* This driver was tested with firmware revision A4.30*/31struct dm355evm_keys {32struct input_dev *input;33struct device *dev;34int irq;35};3637/* These initial keycodes can be remapped */38static const struct key_entry dm355evm_keys[] = {39/*40* Pushbuttons on the EVM board ... note that the labels for these41* are SW10/SW11/etc on the PC board. The left/right orientation42* comes only from the firmware's documentation, and presumes the43* power connector is immediately in front of you and the IR sensor44* is to the right. (That is, rotate the board counter-clockwise45* by 90 degrees from the SW10/etc and "DM355 EVM" labels.)46*/47{ KE_KEY, 0x00d8, { KEY_OK } }, /* SW12 */48{ KE_KEY, 0x00b8, { KEY_UP } }, /* SW13 */49{ KE_KEY, 0x00e8, { KEY_DOWN } }, /* SW11 */50{ KE_KEY, 0x0078, { KEY_LEFT } }, /* SW14 */51{ KE_KEY, 0x00f0, { KEY_RIGHT } }, /* SW10 */5253/*54* IR buttons ... codes assigned to match the universal remote55* provided with the EVM (Philips PM4S) using DVD code 0020.56*57* These event codes match firmware documentation, but other58* remote controls could easily send more RC5-encoded events.59* The PM4S manual was used in several cases to help select60* a keycode reflecting the intended usage.61*62* RC5 codes are 14 bits, with two start bits (0x3 prefix)63* and a toggle bit (masked out below).64*/65{ KE_KEY, 0x300c, { KEY_POWER } }, /* NOTE: docs omit this */66{ KE_KEY, 0x3000, { KEY_NUMERIC_0 } },67{ KE_KEY, 0x3001, { KEY_NUMERIC_1 } },68{ KE_KEY, 0x3002, { KEY_NUMERIC_2 } },69{ KE_KEY, 0x3003, { KEY_NUMERIC_3 } },70{ KE_KEY, 0x3004, { KEY_NUMERIC_4 } },71{ KE_KEY, 0x3005, { KEY_NUMERIC_5 } },72{ KE_KEY, 0x3006, { KEY_NUMERIC_6 } },73{ KE_KEY, 0x3007, { KEY_NUMERIC_7 } },74{ KE_KEY, 0x3008, { KEY_NUMERIC_8 } },75{ KE_KEY, 0x3009, { KEY_NUMERIC_9 } },76{ KE_KEY, 0x3022, { KEY_ENTER } },77{ KE_KEY, 0x30ec, { KEY_MODE } }, /* "tv/vcr/..." */78{ KE_KEY, 0x300f, { KEY_SELECT } }, /* "info" */79{ KE_KEY, 0x3020, { KEY_CHANNELUP } }, /* "up" */80{ KE_KEY, 0x302e, { KEY_MENU } }, /* "in/out" */81{ KE_KEY, 0x3011, { KEY_VOLUMEDOWN } }, /* "left" */82{ KE_KEY, 0x300d, { KEY_MUTE } }, /* "ok" */83{ KE_KEY, 0x3010, { KEY_VOLUMEUP } }, /* "right" */84{ KE_KEY, 0x301e, { KEY_SUBTITLE } }, /* "cc" */85{ KE_KEY, 0x3021, { KEY_CHANNELDOWN } },/* "down" */86{ KE_KEY, 0x3022, { KEY_PREVIOUS } },87{ KE_KEY, 0x3026, { KEY_SLEEP } },88{ KE_KEY, 0x3172, { KEY_REWIND } }, /* NOTE: docs wrongly say 0x30ca */89{ KE_KEY, 0x3175, { KEY_PLAY } },90{ KE_KEY, 0x3174, { KEY_FASTFORWARD } },91{ KE_KEY, 0x3177, { KEY_RECORD } },92{ KE_KEY, 0x3176, { KEY_STOP } },93{ KE_KEY, 0x3169, { KEY_PAUSE } },94};9596/*97* Because we communicate with the MSP430 using I2C, and all I2C calls98* in Linux sleep, we use a threaded IRQ handler. The IRQ itself is99* active low, but we go through the GPIO controller so we can trigger100* on falling edges and not worry about enabling/disabling the IRQ in101* the keypress handling path.102*/103static irqreturn_t dm355evm_keys_irq(int irq, void *_keys)104{105static u16 last_event;106struct dm355evm_keys *keys = _keys;107const struct key_entry *ke;108unsigned int keycode;109int status;110u16 event;111112/* For simplicity we ignore INPUT_COUNT and just read113* events until we get the "queue empty" indicator.114* Reading INPUT_LOW decrements the count.115*/116for (;;) {117status = dm355evm_msp_read(DM355EVM_MSP_INPUT_HIGH);118if (status < 0) {119dev_dbg(keys->dev, "input high err %d\n",120status);121break;122}123event = status << 8;124125status = dm355evm_msp_read(DM355EVM_MSP_INPUT_LOW);126if (status < 0) {127dev_dbg(keys->dev, "input low err %d\n",128status);129break;130}131event |= status;132if (event == 0xdead)133break;134135/* Press and release a button: two events, same code.136* Press and hold (autorepeat), then release: N events137* (N > 2), same code. For RC5 buttons the toggle bits138* distinguish (for example) "1-autorepeat" from "1 1";139* but PCB buttons don't support that bit.140*141* So we must synthesize release events. We do that by142* mapping events to a press/release event pair; then143* to avoid adding extra events, skip the second event144* of each pair.145*/146if (event == last_event) {147last_event = 0;148continue;149}150last_event = event;151152/* ignore the RC5 toggle bit */153event &= ~0x0800;154155/* find the key, or report it as unknown */156ke = sparse_keymap_entry_from_scancode(keys->input, event);157keycode = ke ? ke->keycode : KEY_UNKNOWN;158dev_dbg(keys->dev,159"input event 0x%04x--> keycode %d\n",160event, keycode);161162/* report press + release */163input_report_key(keys->input, keycode, 1);164input_sync(keys->input);165input_report_key(keys->input, keycode, 0);166input_sync(keys->input);167}168169return IRQ_HANDLED;170}171172/*----------------------------------------------------------------------*/173174static int __devinit dm355evm_keys_probe(struct platform_device *pdev)175{176struct dm355evm_keys *keys;177struct input_dev *input;178int status;179180/* allocate instance struct and input dev */181keys = kzalloc(sizeof *keys, GFP_KERNEL);182input = input_allocate_device();183if (!keys || !input) {184status = -ENOMEM;185goto fail1;186}187188keys->dev = &pdev->dev;189keys->input = input;190191/* set up "threaded IRQ handler" */192status = platform_get_irq(pdev, 0);193if (status < 0)194goto fail1;195keys->irq = status;196197input_set_drvdata(input, keys);198199input->name = "DM355 EVM Controls";200input->phys = "dm355evm/input0";201input->dev.parent = &pdev->dev;202203input->id.bustype = BUS_I2C;204input->id.product = 0x0355;205input->id.version = dm355evm_msp_read(DM355EVM_MSP_FIRMREV);206207status = sparse_keymap_setup(input, dm355evm_keys, NULL);208if (status)209goto fail1;210211/* REVISIT: flush the event queue? */212213status = request_threaded_irq(keys->irq, NULL, dm355evm_keys_irq,214IRQF_TRIGGER_FALLING, dev_name(&pdev->dev), keys);215if (status < 0)216goto fail2;217218/* register */219status = input_register_device(input);220if (status < 0)221goto fail3;222223platform_set_drvdata(pdev, keys);224225return 0;226227fail3:228free_irq(keys->irq, keys);229fail2:230sparse_keymap_free(input);231fail1:232input_free_device(input);233kfree(keys);234dev_err(&pdev->dev, "can't register, err %d\n", status);235236return status;237}238239static int __devexit dm355evm_keys_remove(struct platform_device *pdev)240{241struct dm355evm_keys *keys = platform_get_drvdata(pdev);242243free_irq(keys->irq, keys);244sparse_keymap_free(keys->input);245input_unregister_device(keys->input);246kfree(keys);247248return 0;249}250251/* REVISIT: add suspend/resume when DaVinci supports it. The IRQ should252* be able to wake up the system. When device_may_wakeup(&pdev->dev), call253* enable_irq_wake() on suspend, and disable_irq_wake() on resume.254*/255256/*257* I2C is used to talk to the MSP430, but this platform device is258* exposed by an MFD driver that manages I2C communications.259*/260static struct platform_driver dm355evm_keys_driver = {261.probe = dm355evm_keys_probe,262.remove = __devexit_p(dm355evm_keys_remove),263.driver = {264.owner = THIS_MODULE,265.name = "dm355evm_keys",266},267};268269static int __init dm355evm_keys_init(void)270{271return platform_driver_register(&dm355evm_keys_driver);272}273module_init(dm355evm_keys_init);274275static void __exit dm355evm_keys_exit(void)276{277platform_driver_unregister(&dm355evm_keys_driver);278}279module_exit(dm355evm_keys_exit);280281MODULE_LICENSE("GPL");282283284