Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pxa930_trkball.c
Go to the documentation of this file.
1 /*
2  * PXA930 track ball mouse driver
3  *
4  * Copyright (C) 2007 Marvell International Ltd.
5  * 2008-02-28: Yong Yao <[email protected]>
6  * initial version
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11  */
12 
13 #include <linux/init.h>
14 #include <linux/input.h>
15 #include <linux/interrupt.h>
16 #include <linux/module.h>
17 #include <linux/platform_device.h>
18 #include <linux/delay.h>
19 #include <linux/io.h>
20 #include <linux/slab.h>
21 
22 #include <mach/hardware.h>
24 
25 /* Trackball Controller Register Definitions */
26 #define TBCR (0x000C)
27 #define TBCNTR (0x0010)
28 #define TBSBC (0x0014)
29 
30 #define TBCR_TBRST (1 << 1)
31 #define TBCR_TBSB (1 << 10)
32 
33 #define TBCR_Y_FLT(n) (((n) & 0xf) << 6)
34 #define TBCR_X_FLT(n) (((n) & 0xf) << 2)
35 
36 #define TBCNTR_YM(n) (((n) >> 24) & 0xff)
37 #define TBCNTR_YP(n) (((n) >> 16) & 0xff)
38 #define TBCNTR_XM(n) (((n) >> 8) & 0xff)
39 #define TBCNTR_XP(n) ((n) & 0xff)
40 
41 #define TBSBC_TBSBC (0x1)
42 
45 
46  /* Memory Mapped Register */
47  struct resource *mem;
49 
50  struct input_dev *input;
51 };
52 
53 static irqreturn_t pxa930_trkball_interrupt(int irq, void *dev_id)
54 {
55  struct pxa930_trkball *trkball = dev_id;
56  struct input_dev *input = trkball->input;
57  int tbcntr, x, y;
58 
59  /* According to the spec software must read TBCNTR twice:
60  * if the read value is the same, the reading is valid
61  */
62  tbcntr = __raw_readl(trkball->mmio_base + TBCNTR);
63 
64  if (tbcntr == __raw_readl(trkball->mmio_base + TBCNTR)) {
65  x = (TBCNTR_XP(tbcntr) - TBCNTR_XM(tbcntr)) / 2;
66  y = (TBCNTR_YP(tbcntr) - TBCNTR_YM(tbcntr)) / 2;
67 
68  input_report_rel(input, REL_X, x);
69  input_report_rel(input, REL_Y, y);
70  input_sync(input);
71  }
72 
74  __raw_writel(0, trkball->mmio_base + TBSBC);
75 
76  return IRQ_HANDLED;
77 }
78 
79 /* For TBCR, we need to wait for a while to make sure it has been modified. */
80 static int write_tbcr(struct pxa930_trkball *trkball, int v)
81 {
82  int i = 100;
83 
84  __raw_writel(v, trkball->mmio_base + TBCR);
85 
86  while (--i) {
87  if (__raw_readl(trkball->mmio_base + TBCR) == v)
88  break;
89  msleep(1);
90  }
91 
92  if (i == 0) {
93  pr_err("%s: timed out writing TBCR(%x)!\n", __func__, v);
94  return -ETIMEDOUT;
95  }
96 
97  return 0;
98 }
99 
100 static void pxa930_trkball_config(struct pxa930_trkball *trkball)
101 {
102  uint32_t tbcr;
103 
104  /* According to spec, need to write the filters of x,y to 0xf first! */
105  tbcr = __raw_readl(trkball->mmio_base + TBCR);
106  write_tbcr(trkball, tbcr | TBCR_X_FLT(0xf) | TBCR_Y_FLT(0xf));
107  write_tbcr(trkball, TBCR_X_FLT(trkball->pdata->x_filter) |
108  TBCR_Y_FLT(trkball->pdata->y_filter));
109 
110  /* According to spec, set TBCR_TBRST first, before clearing it! */
111  tbcr = __raw_readl(trkball->mmio_base + TBCR);
112  write_tbcr(trkball, tbcr | TBCR_TBRST);
113  write_tbcr(trkball, tbcr & ~TBCR_TBRST);
114 
116  __raw_writel(0, trkball->mmio_base + TBSBC);
117 
118  pr_debug("%s: final TBCR=%x!\n", __func__,
119  __raw_readl(trkball->mmio_base + TBCR));
120 }
121 
122 static int pxa930_trkball_open(struct input_dev *dev)
123 {
124  struct pxa930_trkball *trkball = input_get_drvdata(dev);
125 
126  pxa930_trkball_config(trkball);
127 
128  return 0;
129 }
130 
131 static void pxa930_trkball_disable(struct pxa930_trkball *trkball)
132 {
133  uint32_t tbcr = __raw_readl(trkball->mmio_base + TBCR);
134 
135  /* Held in reset, gate the 32-KHz input clock off */
136  write_tbcr(trkball, tbcr | TBCR_TBRST);
137 }
138 
139 static void pxa930_trkball_close(struct input_dev *dev)
140 {
141  struct pxa930_trkball *trkball = input_get_drvdata(dev);
142 
143  pxa930_trkball_disable(trkball);
144 }
145 
146 static int __devinit pxa930_trkball_probe(struct platform_device *pdev)
147 {
148  struct pxa930_trkball *trkball;
149  struct input_dev *input;
150  struct resource *res;
151  int irq, error;
152 
153  irq = platform_get_irq(pdev, 0);
154  if (irq < 0) {
155  dev_err(&pdev->dev, "failed to get trkball irq\n");
156  return -ENXIO;
157  }
158 
159  res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
160  if (!res) {
161  dev_err(&pdev->dev, "failed to get register memory\n");
162  return -ENXIO;
163  }
164 
165  trkball = kzalloc(sizeof(struct pxa930_trkball), GFP_KERNEL);
166  if (!trkball)
167  return -ENOMEM;
168 
169  trkball->pdata = pdev->dev.platform_data;
170  if (!trkball->pdata) {
171  dev_err(&pdev->dev, "no platform data defined\n");
172  error = -EINVAL;
173  goto failed;
174  }
175 
176  trkball->mmio_base = ioremap_nocache(res->start, resource_size(res));
177  if (!trkball->mmio_base) {
178  dev_err(&pdev->dev, "failed to ioremap registers\n");
179  error = -ENXIO;
180  goto failed;
181  }
182 
183  /* held the module in reset, will be enabled in open() */
184  pxa930_trkball_disable(trkball);
185 
186  error = request_irq(irq, pxa930_trkball_interrupt, 0,
187  pdev->name, trkball);
188  if (error) {
189  dev_err(&pdev->dev, "failed to request irq: %d\n", error);
190  goto failed_free_io;
191  }
192 
193  platform_set_drvdata(pdev, trkball);
194 
195  input = input_allocate_device();
196  if (!input) {
197  dev_err(&pdev->dev, "failed to allocate input device\n");
198  error = -ENOMEM;
199  goto failed_free_irq;
200  }
201 
202  input->name = pdev->name;
203  input->id.bustype = BUS_HOST;
204  input->open = pxa930_trkball_open;
205  input->close = pxa930_trkball_close;
206  input->dev.parent = &pdev->dev;
207  input_set_drvdata(input, trkball);
208 
209  trkball->input = input;
210 
211  input_set_capability(input, EV_REL, REL_X);
212  input_set_capability(input, EV_REL, REL_Y);
213 
214  error = input_register_device(input);
215  if (error) {
216  dev_err(&pdev->dev, "unable to register input device\n");
217  goto failed_free_input;
218  }
219 
220  return 0;
221 
222 failed_free_input:
223  input_free_device(input);
224 failed_free_irq:
225  free_irq(irq, trkball);
226 failed_free_io:
227  iounmap(trkball->mmio_base);
228 failed:
229  kfree(trkball);
230  return error;
231 }
232 
233 static int __devexit pxa930_trkball_remove(struct platform_device *pdev)
234 {
235  struct pxa930_trkball *trkball = platform_get_drvdata(pdev);
236  int irq = platform_get_irq(pdev, 0);
237 
238  input_unregister_device(trkball->input);
239  free_irq(irq, trkball);
240  iounmap(trkball->mmio_base);
241  kfree(trkball);
242 
243  return 0;
244 }
245 
246 static struct platform_driver pxa930_trkball_driver = {
247  .driver = {
248  .name = "pxa930-trkball",
249  },
250  .probe = pxa930_trkball_probe,
251  .remove = __devexit_p(pxa930_trkball_remove),
252 };
253 module_platform_driver(pxa930_trkball_driver);
254 
255 MODULE_AUTHOR("Yong Yao <[email protected]>");
256 MODULE_DESCRIPTION("PXA930 Trackball Mouse Driver");
257 MODULE_LICENSE("GPL");