OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [input/] [keyboard/] [pxa27x_keyboard.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 * linux/drivers/input/keyboard/pxa27x_keyboard.c
3
 *
4
 * Driver for the pxa27x matrix keyboard controller.
5
 *
6
 * Created:     Feb 22, 2007
7
 * Author:      Rodolfo Giometti <giometti@linux.it>
8
 *
9
 * Based on a previous implementations by Kevin O'Connor
10
 * <kevin_at_koconnor.net> and Alex Osborne <bobofdoom@gmail.com> and
11
 * on some suggestions by Nicolas Pitre <nico@cam.org>.
12
 *
13
 * This program is free software; you can redistribute it and/or modify
14
 * it under the terms of the GNU General Public License version 2 as
15
 * published by the Free Software Foundation.
16
 */
17
 
18
 
19
#include <linux/kernel.h>
20
#include <linux/module.h>
21
#include <linux/init.h>
22
#include <linux/interrupt.h>
23
#include <linux/input.h>
24
#include <linux/device.h>
25
#include <linux/platform_device.h>
26
#include <linux/clk.h>
27
#include <linux/err.h>
28
 
29
#include <asm/mach-types.h>
30
#include <asm/mach/arch.h>
31
#include <asm/mach/map.h>
32
 
33
#include <asm/arch/hardware.h>
34
#include <asm/arch/pxa-regs.h>
35
#include <asm/arch/irqs.h>
36
#include <asm/arch/pxa27x_keyboard.h>
37
 
38
#define DRIVER_NAME             "pxa27x-keyboard"
39
 
40
#define KPASMKP(col)            (col/2 == 0 ? KPASMKP0 : \
41
                                 col/2 == 1 ? KPASMKP1 : \
42
                                 col/2 == 2 ? KPASMKP2 : KPASMKP3)
43
#define KPASMKPx_MKC(row, col)  (1 << (row + 16 * (col % 2)))
44
 
45
static struct clk *pxakbd_clk;
46
 
47
static irqreturn_t pxakbd_irq_handler(int irq, void *dev_id)
48
{
49
        struct platform_device *pdev = dev_id;
50
        struct pxa27x_keyboard_platform_data *pdata = pdev->dev.platform_data;
51
        struct input_dev *input_dev = platform_get_drvdata(pdev);
52
        unsigned long kpc = KPC;
53
        int p, row, col, rel;
54
 
55
        if (kpc & KPC_DI) {
56
                unsigned long kpdk = KPDK;
57
 
58
                if (!(kpdk & KPDK_DKP)) {
59
                        /* better luck next time */
60
                } else if (kpc & KPC_REE0) {
61
                        unsigned long kprec = KPREC;
62
                        KPREC = 0x7f;
63
 
64
                        if (kprec & KPREC_OF0)
65
                                rel = (kprec & 0xff) + 0x7f;
66
                        else if (kprec & KPREC_UF0)
67
                                rel = (kprec & 0xff) - 0x7f - 0xff;
68
                        else
69
                                rel = (kprec & 0xff) - 0x7f;
70
 
71
                        if (rel) {
72
                                input_report_rel(input_dev, REL_WHEEL, rel);
73
                                input_sync(input_dev);
74
                        }
75
                }
76
        }
77
 
78
        if (kpc & KPC_MI) {
79
                /* report the status of every button */
80
                for (row = 0; row < pdata->nr_rows; row++) {
81
                        for (col = 0; col < pdata->nr_cols; col++) {
82
                                p = KPASMKP(col) & KPASMKPx_MKC(row, col) ?
83
                                        1 : 0;
84
                                pr_debug("keycode %x - pressed %x\n",
85
                                                pdata->keycodes[row][col], p);
86
                                input_report_key(input_dev,
87
                                                pdata->keycodes[row][col], p);
88
                        }
89
                }
90
                input_sync(input_dev);
91
        }
92
 
93
        return IRQ_HANDLED;
94
}
95
 
96
static int pxakbd_open(struct input_dev *dev)
97
{
98
        /* Set keypad control register */
99
        KPC |= (KPC_ASACT |
100
                KPC_MS_ALL |
101
                (2 << 6) | KPC_REE0 | KPC_DK_DEB_SEL |
102
                KPC_ME | KPC_MIE | KPC_DE | KPC_DIE);
103
 
104
        KPC &= ~KPC_AS;         /* disable automatic scan */
105
        KPC &= ~KPC_IMKP;       /* do not ignore multiple keypresses */
106
 
107
        /* Set rotary count to mid-point value */
108
        KPREC = 0x7F;
109
 
110
        /* Enable unit clock */
111
        clk_enable(pxakbd_clk);
112
 
113
        return 0;
114
}
115
 
116
static void pxakbd_close(struct input_dev *dev)
117
{
118
        /* Disable clock unit */
119
        clk_disable(pxakbd_clk);
120
}
121
 
122
#ifdef CONFIG_PM
123
static int pxakbd_suspend(struct platform_device *pdev, pm_message_t state)
124
{
125
        struct pxa27x_keyboard_platform_data *pdata = pdev->dev.platform_data;
126
 
127
        /* Save controller status */
128
        pdata->reg_kpc = KPC;
129
        pdata->reg_kprec = KPREC;
130
 
131
        return 0;
132
}
133
 
134
static int pxakbd_resume(struct platform_device *pdev)
135
{
136
        struct pxa27x_keyboard_platform_data *pdata = pdev->dev.platform_data;
137
        struct input_dev *input_dev = platform_get_drvdata(pdev);
138
 
139
        mutex_lock(&input_dev->mutex);
140
 
141
        if (input_dev->users) {
142
                /* Restore controller status */
143
                KPC = pdata->reg_kpc;
144
                KPREC = pdata->reg_kprec;
145
 
146
                /* Enable unit clock */
147
                clk_disable(pxakbd_clk);
148
                clk_enable(pxakbd_clk);
149
        }
150
 
151
        mutex_unlock(&input_dev->mutex);
152
 
153
        return 0;
154
}
155
#else
156
#define pxakbd_suspend  NULL
157
#define pxakbd_resume   NULL
158
#endif
159
 
160
static int __devinit pxakbd_probe(struct platform_device *pdev)
161
{
162
        struct pxa27x_keyboard_platform_data *pdata = pdev->dev.platform_data;
163
        struct input_dev *input_dev;
164
        int i, row, col, error;
165
 
166
        pxakbd_clk = clk_get(&pdev->dev, "KBDCLK");
167
        if (IS_ERR(pxakbd_clk)) {
168
                error = PTR_ERR(pxakbd_clk);
169
                goto err_clk;
170
        }
171
 
172
        /* Create and register the input driver. */
173
        input_dev = input_allocate_device();
174
        if (!input_dev) {
175
                printk(KERN_ERR "Cannot request keypad device\n");
176
                error = -ENOMEM;
177
                goto err_alloc;
178
        }
179
 
180
        input_dev->name = DRIVER_NAME;
181
        input_dev->id.bustype = BUS_HOST;
182
        input_dev->open = pxakbd_open;
183
        input_dev->close = pxakbd_close;
184
        input_dev->dev.parent = &pdev->dev;
185
 
186
        input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP) |
187
                BIT_MASK(EV_REL);
188
        input_dev->relbit[BIT_WORD(REL_WHEEL)] = BIT_MASK(REL_WHEEL);
189
        for (row = 0; row < pdata->nr_rows; row++) {
190
                for (col = 0; col < pdata->nr_cols; col++) {
191
                        int code = pdata->keycodes[row][col];
192
                        if (code > 0)
193
                                set_bit(code, input_dev->keybit);
194
                }
195
        }
196
 
197
        error = request_irq(IRQ_KEYPAD, pxakbd_irq_handler, IRQF_DISABLED,
198
                            DRIVER_NAME, pdev);
199
        if (error) {
200
                printk(KERN_ERR "Cannot request keypad IRQ\n");
201
                goto err_free_dev;
202
        }
203
 
204
        platform_set_drvdata(pdev, input_dev);
205
 
206
        /* Register the input device */
207
        error = input_register_device(input_dev);
208
        if (error)
209
                goto err_free_irq;
210
 
211
        /* Setup GPIOs. */
212
        for (i = 0; i < pdata->nr_rows + pdata->nr_cols; i++)
213
                pxa_gpio_mode(pdata->gpio_modes[i]);
214
 
215
        /*
216
         * Store rows/cols info into keyboard registers.
217
         */
218
 
219
        KPC |= (pdata->nr_rows - 1) << 26;
220
        KPC |= (pdata->nr_cols - 1) << 23;
221
 
222
        for (col = 0; col < pdata->nr_cols; col++)
223
                KPC |= KPC_MS0 << col;
224
 
225
        return 0;
226
 
227
 err_free_irq:
228
        platform_set_drvdata(pdev, NULL);
229
        free_irq(IRQ_KEYPAD, pdev);
230
 err_free_dev:
231
        input_free_device(input_dev);
232
 err_alloc:
233
        clk_put(pxakbd_clk);
234
 err_clk:
235
        return error;
236
}
237
 
238
static int __devexit pxakbd_remove(struct platform_device *pdev)
239
{
240
        struct input_dev *input_dev = platform_get_drvdata(pdev);
241
 
242
        input_unregister_device(input_dev);
243
        free_irq(IRQ_KEYPAD, pdev);
244
        clk_put(pxakbd_clk);
245
        platform_set_drvdata(pdev, NULL);
246
 
247
        return 0;
248
}
249
 
250
static struct platform_driver pxakbd_driver = {
251
        .probe          = pxakbd_probe,
252
        .remove         = __devexit_p(pxakbd_remove),
253
        .suspend        = pxakbd_suspend,
254
        .resume         = pxakbd_resume,
255
        .driver         = {
256
                .name   = DRIVER_NAME,
257
        },
258
};
259
 
260
static int __init pxakbd_init(void)
261
{
262
        return platform_driver_register(&pxakbd_driver);
263
}
264
 
265
static void __exit pxakbd_exit(void)
266
{
267
        platform_driver_unregister(&pxakbd_driver);
268
}
269
 
270
module_init(pxakbd_init);
271
module_exit(pxakbd_exit);
272
 
273
MODULE_DESCRIPTION("PXA27x Matrix Keyboard Driver");
274
MODULE_LICENSE("GPL");

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.