diff options
author | Matti J. Aaltonen <matti.j.aaltonen@nokia.com> | 2011-01-12 20:00:47 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-01-13 11:03:19 -0500 |
commit | 0329326e85aaa30fb8d427828c718d565c287385 (patch) | |
tree | ab6d9c1e9c6a56ebca273b9d36d76a4a3eb60b23 /drivers/nfc | |
parent | 6164281ab7a4d3bd42588d6b25984e960a2e032f (diff) |
NFC: Driver for NXP Semiconductors PN544 NFC chip.
Creates a new "Near Field Communication" subsystem in drivers/nfc.
http://en.wikipedia.org/wiki/Near_Field_Communication is useful ;)
This is a driver for the pn544 NFC device. The driver transfers
ETSI messages between the device and the user space.
Signed-off-by: Matti J. Aaltonen <matti.j.aaltonen@nokia.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/nfc')
-rw-r--r-- | drivers/nfc/Kconfig | 30 | ||||
-rw-r--r-- | drivers/nfc/Makefile | 5 | ||||
-rw-r--r-- | drivers/nfc/pn544.c | 891 |
3 files changed, 926 insertions, 0 deletions
diff --git a/drivers/nfc/Kconfig b/drivers/nfc/Kconfig new file mode 100644 index 000000000000..ffedfd492754 --- /dev/null +++ b/drivers/nfc/Kconfig | |||
@@ -0,0 +1,30 @@ | |||
1 | # | ||
2 | # Near Field Communication (NFC) devices | ||
3 | # | ||
4 | |||
5 | menuconfig NFC_DEVICES | ||
6 | bool "NFC devices" | ||
7 | default n | ||
8 | ---help--- | ||
9 | You'll have to say Y if your computer contains an NFC device that | ||
10 | you want to use under Linux. | ||
11 | |||
12 | You can say N here if you don't have any Near Field Communication | ||
13 | devices connected to your computer. | ||
14 | |||
15 | if NFC_DEVICES | ||
16 | |||
17 | config PN544_NFC | ||
18 | tristate "PN544 NFC driver" | ||
19 | depends on I2C | ||
20 | select CRC_CCITT | ||
21 | default n | ||
22 | ---help--- | ||
23 | Say yes if you want PN544 Near Field Communication driver. | ||
24 | This is for i2c connected version. If unsure, say N here. | ||
25 | |||
26 | To compile this driver as a module, choose m here. The module will | ||
27 | be called pn544. | ||
28 | |||
29 | |||
30 | endif # NFC_DEVICES | ||
diff --git a/drivers/nfc/Makefile b/drivers/nfc/Makefile new file mode 100644 index 000000000000..a4efb164ec49 --- /dev/null +++ b/drivers/nfc/Makefile | |||
@@ -0,0 +1,5 @@ | |||
1 | # | ||
2 | # Makefile for nfc devices | ||
3 | # | ||
4 | |||
5 | obj-$(CONFIG_PN544_NFC) += pn544.o | ||
diff --git a/drivers/nfc/pn544.c b/drivers/nfc/pn544.c new file mode 100644 index 000000000000..401c44b6eadb --- /dev/null +++ b/drivers/nfc/pn544.c | |||
@@ -0,0 +1,891 @@ | |||
1 | /* | ||
2 | * Driver for the PN544 NFC chip. | ||
3 | * | ||
4 | * Copyright (C) Nokia Corporation | ||
5 | * | ||
6 | * Author: Jari Vanhala <ext-jari.vanhala@nokia.com> | ||
7 | * Contact: Matti Aaltonen <matti.j.aaltonen@nokia.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * version 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
21 | */ | ||
22 | |||
23 | #include <linux/completion.h> | ||
24 | #include <linux/crc-ccitt.h> | ||
25 | #include <linux/delay.h> | ||
26 | #include <linux/interrupt.h> | ||
27 | #include <linux/kernel.h> | ||
28 | #include <linux/miscdevice.h> | ||
29 | #include <linux/module.h> | ||
30 | #include <linux/mutex.h> | ||
31 | #include <linux/nfc/pn544.h> | ||
32 | #include <linux/poll.h> | ||
33 | #include <linux/regulator/consumer.h> | ||
34 | #include <linux/serial_core.h> /* for TCGETS */ | ||
35 | #include <linux/slab.h> | ||
36 | |||
37 | #define DRIVER_CARD "PN544 NFC" | ||
38 | #define DRIVER_DESC "NFC driver for PN544" | ||
39 | |||
40 | static struct i2c_device_id pn544_id_table[] = { | ||
41 | { PN544_DRIVER_NAME, 0 }, | ||
42 | { } | ||
43 | }; | ||
44 | MODULE_DEVICE_TABLE(i2c, pn544_id_table); | ||
45 | |||
46 | #define HCI_MODE 0 | ||
47 | #define FW_MODE 1 | ||
48 | |||
49 | enum pn544_state { | ||
50 | PN544_ST_COLD, | ||
51 | PN544_ST_FW_READY, | ||
52 | PN544_ST_READY, | ||
53 | }; | ||
54 | |||
55 | enum pn544_irq { | ||
56 | PN544_NONE, | ||
57 | PN544_INT, | ||
58 | }; | ||
59 | |||
60 | struct pn544_info { | ||
61 | struct miscdevice miscdev; | ||
62 | struct i2c_client *i2c_dev; | ||
63 | struct regulator_bulk_data regs[2]; | ||
64 | |||
65 | enum pn544_state state; | ||
66 | wait_queue_head_t read_wait; | ||
67 | loff_t read_offset; | ||
68 | enum pn544_irq read_irq; | ||
69 | struct mutex read_mutex; /* Serialize read_irq access */ | ||
70 | struct mutex mutex; /* Serialize info struct access */ | ||
71 | u8 *buf; | ||
72 | unsigned int buflen; | ||
73 | }; | ||
74 | |||
75 | static const char reg_vdd_io[] = "Vdd_IO"; | ||
76 | static const char reg_vbat[] = "VBat"; | ||
77 | |||
78 | /* sysfs interface */ | ||
79 | static ssize_t pn544_test(struct device *dev, | ||
80 | struct device_attribute *attr, char *buf) | ||
81 | { | ||
82 | struct pn544_info *info = dev_get_drvdata(dev); | ||
83 | struct i2c_client *client = info->i2c_dev; | ||
84 | struct pn544_nfc_platform_data *pdata = client->dev.platform_data; | ||
85 | |||
86 | return snprintf(buf, PAGE_SIZE, "%d\n", pdata->test()); | ||
87 | } | ||
88 | |||
89 | static int pn544_enable(struct pn544_info *info, int mode) | ||
90 | { | ||
91 | struct pn544_nfc_platform_data *pdata; | ||
92 | struct i2c_client *client = info->i2c_dev; | ||
93 | |||
94 | int r; | ||
95 | |||
96 | r = regulator_bulk_enable(ARRAY_SIZE(info->regs), info->regs); | ||
97 | if (r < 0) | ||
98 | return r; | ||
99 | |||
100 | pdata = client->dev.platform_data; | ||
101 | info->read_irq = PN544_NONE; | ||
102 | if (pdata->enable) | ||
103 | pdata->enable(mode); | ||
104 | |||
105 | if (mode) { | ||
106 | info->state = PN544_ST_FW_READY; | ||
107 | dev_dbg(&client->dev, "now in FW-mode\n"); | ||
108 | } else { | ||
109 | info->state = PN544_ST_READY; | ||
110 | dev_dbg(&client->dev, "now in HCI-mode\n"); | ||
111 | } | ||
112 | |||
113 | usleep_range(10000, 15000); | ||
114 | |||
115 | return 0; | ||
116 | } | ||
117 | |||
118 | static void pn544_disable(struct pn544_info *info) | ||
119 | { | ||
120 | struct pn544_nfc_platform_data *pdata; | ||
121 | struct i2c_client *client = info->i2c_dev; | ||
122 | |||
123 | pdata = client->dev.platform_data; | ||
124 | if (pdata->disable) | ||
125 | pdata->disable(); | ||
126 | |||
127 | info->state = PN544_ST_COLD; | ||
128 | |||
129 | dev_dbg(&client->dev, "Now in OFF-mode\n"); | ||
130 | |||
131 | msleep(PN544_RESETVEN_TIME); | ||
132 | |||
133 | info->read_irq = PN544_NONE; | ||
134 | regulator_bulk_disable(ARRAY_SIZE(info->regs), info->regs); | ||
135 | } | ||
136 | |||
137 | static int check_crc(u8 *buf, int buflen) | ||
138 | { | ||
139 | u8 len; | ||
140 | u16 crc; | ||
141 | |||
142 | len = buf[0] + 1; | ||
143 | if (len < 4 || len != buflen || len > PN544_MSG_MAX_SIZE) { | ||
144 | pr_err(PN544_DRIVER_NAME | ||
145 | ": CRC; corrupt packet len %u (%d)\n", len, buflen); | ||
146 | print_hex_dump(KERN_DEBUG, "crc: ", DUMP_PREFIX_NONE, | ||
147 | 16, 2, buf, buflen, false); | ||
148 | return -EPERM; | ||
149 | } | ||
150 | crc = crc_ccitt(0xffff, buf, len - 2); | ||
151 | crc = ~crc; | ||
152 | |||
153 | if (buf[len-2] != (crc & 0xff) || buf[len-1] != (crc >> 8)) { | ||
154 | pr_err(PN544_DRIVER_NAME ": CRC error 0x%x != 0x%x 0x%x\n", | ||
155 | crc, buf[len-1], buf[len-2]); | ||
156 | |||
157 | print_hex_dump(KERN_DEBUG, "crc: ", DUMP_PREFIX_NONE, | ||
158 | 16, 2, buf, buflen, false); | ||
159 | return -EPERM; | ||
160 | } | ||
161 | return 0; | ||
162 | } | ||
163 | |||
164 | static int pn544_i2c_write(struct i2c_client *client, u8 *buf, int len) | ||
165 | { | ||
166 | int r; | ||
167 | |||
168 | if (len < 4 || len != (buf[0] + 1)) { | ||
169 | dev_err(&client->dev, "%s: Illegal message length: %d\n", | ||
170 | __func__, len); | ||
171 | return -EINVAL; | ||
172 | } | ||
173 | |||
174 | if (check_crc(buf, len)) | ||
175 | return -EINVAL; | ||
176 | |||
177 | usleep_range(3000, 6000); | ||
178 | |||
179 | r = i2c_master_send(client, buf, len); | ||
180 | dev_dbg(&client->dev, "send: %d\n", r); | ||
181 | |||
182 | if (r == -EREMOTEIO) { /* Retry, chip was in standby */ | ||
183 | usleep_range(6000, 10000); | ||
184 | r = i2c_master_send(client, buf, len); | ||
185 | dev_dbg(&client->dev, "send2: %d\n", r); | ||
186 | } | ||
187 | |||
188 | if (r != len) | ||
189 | return -EREMOTEIO; | ||
190 | |||
191 | return r; | ||
192 | } | ||
193 | |||
194 | static int pn544_i2c_read(struct i2c_client *client, u8 *buf, int buflen) | ||
195 | { | ||
196 | int r; | ||
197 | u8 len; | ||
198 | |||
199 | /* | ||
200 | * You could read a packet in one go, but then you'd need to read | ||
201 | * max size and rest would be 0xff fill, so we do split reads. | ||
202 | */ | ||
203 | r = i2c_master_recv(client, &len, 1); | ||
204 | dev_dbg(&client->dev, "recv1: %d\n", r); | ||
205 | |||
206 | if (r != 1) | ||
207 | return -EREMOTEIO; | ||
208 | |||
209 | if (len < PN544_LLC_HCI_OVERHEAD) | ||
210 | len = PN544_LLC_HCI_OVERHEAD; | ||
211 | else if (len > (PN544_MSG_MAX_SIZE - 1)) | ||
212 | len = PN544_MSG_MAX_SIZE - 1; | ||
213 | |||
214 | if (1 + len > buflen) /* len+(data+crc16) */ | ||
215 | return -EMSGSIZE; | ||
216 | |||
217 | buf[0] = len; | ||
218 | |||
219 | r = i2c_master_recv(client, buf + 1, len); | ||
220 | dev_dbg(&client->dev, "recv2: %d\n", r); | ||
221 | |||
222 | if (r != len) | ||
223 | return -EREMOTEIO; | ||
224 | |||
225 | usleep_range(3000, 6000); | ||
226 | |||
227 | return r + 1; | ||
228 | } | ||
229 | |||
230 | static int pn544_fw_write(struct i2c_client *client, u8 *buf, int len) | ||
231 | { | ||
232 | int r; | ||
233 | |||
234 | dev_dbg(&client->dev, "%s\n", __func__); | ||
235 | |||
236 | if (len < PN544_FW_HEADER_SIZE || | ||
237 | (PN544_FW_HEADER_SIZE + (buf[1] << 8) + buf[2]) != len) | ||
238 | return -EINVAL; | ||
239 | |||
240 | r = i2c_master_send(client, buf, len); | ||
241 | dev_dbg(&client->dev, "fw send: %d\n", r); | ||
242 | |||
243 | if (r == -EREMOTEIO) { /* Retry, chip was in standby */ | ||
244 | usleep_range(6000, 10000); | ||
245 | r = i2c_master_send(client, buf, len); | ||
246 | dev_dbg(&client->dev, "fw send2: %d\n", r); | ||
247 | } | ||
248 | |||
249 | if (r != len) | ||
250 | return -EREMOTEIO; | ||
251 | |||
252 | return r; | ||
253 | } | ||
254 | |||
255 | static int pn544_fw_read(struct i2c_client *client, u8 *buf, int buflen) | ||
256 | { | ||
257 | int r, len; | ||
258 | |||
259 | if (buflen < PN544_FW_HEADER_SIZE) | ||
260 | return -EINVAL; | ||
261 | |||
262 | r = i2c_master_recv(client, buf, PN544_FW_HEADER_SIZE); | ||
263 | dev_dbg(&client->dev, "FW recv1: %d\n", r); | ||
264 | |||
265 | if (r < 0) | ||
266 | return r; | ||
267 | |||
268 | if (r < PN544_FW_HEADER_SIZE) | ||
269 | return -EINVAL; | ||
270 | |||
271 | len = (buf[1] << 8) + buf[2]; | ||
272 | if (len == 0) /* just header, no additional data */ | ||
273 | return r; | ||
274 | |||
275 | if (len > buflen - PN544_FW_HEADER_SIZE) | ||
276 | return -EMSGSIZE; | ||
277 | |||
278 | r = i2c_master_recv(client, buf + PN544_FW_HEADER_SIZE, len); | ||
279 | dev_dbg(&client->dev, "fw recv2: %d\n", r); | ||
280 | |||
281 | if (r != len) | ||
282 | return -EINVAL; | ||
283 | |||
284 | return r + PN544_FW_HEADER_SIZE; | ||
285 | } | ||
286 | |||
287 | static irqreturn_t pn544_irq_thread_fn(int irq, void *dev_id) | ||
288 | { | ||
289 | struct pn544_info *info = dev_id; | ||
290 | struct i2c_client *client = info->i2c_dev; | ||
291 | |||
292 | BUG_ON(!info); | ||
293 | BUG_ON(irq != info->i2c_dev->irq); | ||
294 | |||
295 | dev_dbg(&client->dev, "IRQ\n"); | ||
296 | |||
297 | mutex_lock(&info->read_mutex); | ||
298 | info->read_irq = PN544_INT; | ||
299 | mutex_unlock(&info->read_mutex); | ||
300 | |||
301 | wake_up_interruptible(&info->read_wait); | ||
302 | |||
303 | return IRQ_HANDLED; | ||
304 | } | ||
305 | |||
306 | static enum pn544_irq pn544_irq_state(struct pn544_info *info) | ||
307 | { | ||
308 | enum pn544_irq irq; | ||
309 | |||
310 | mutex_lock(&info->read_mutex); | ||
311 | irq = info->read_irq; | ||
312 | mutex_unlock(&info->read_mutex); | ||
313 | /* | ||
314 | * XXX: should we check GPIO-line status directly? | ||
315 | * return pdata->irq_status() ? PN544_INT : PN544_NONE; | ||
316 | */ | ||
317 | |||
318 | return irq; | ||
319 | } | ||
320 | |||
321 | static ssize_t pn544_read(struct file *file, char __user *buf, | ||
322 | size_t count, loff_t *offset) | ||
323 | { | ||
324 | struct pn544_info *info = container_of(file->private_data, | ||
325 | struct pn544_info, miscdev); | ||
326 | struct i2c_client *client = info->i2c_dev; | ||
327 | enum pn544_irq irq; | ||
328 | size_t len; | ||
329 | int r = 0; | ||
330 | |||
331 | dev_dbg(&client->dev, "%s: info: %p, count: %zu\n", __func__, | ||
332 | info, count); | ||
333 | |||
334 | mutex_lock(&info->mutex); | ||
335 | |||
336 | if (info->state == PN544_ST_COLD) { | ||
337 | r = -ENODEV; | ||
338 | goto out; | ||
339 | } | ||
340 | |||
341 | irq = pn544_irq_state(info); | ||
342 | if (irq == PN544_NONE) { | ||
343 | if (file->f_flags & O_NONBLOCK) { | ||
344 | r = -EAGAIN; | ||
345 | goto out; | ||
346 | } | ||
347 | |||
348 | if (wait_event_interruptible(info->read_wait, | ||
349 | (info->read_irq == PN544_INT))) { | ||
350 | r = -ERESTARTSYS; | ||
351 | goto out; | ||
352 | } | ||
353 | } | ||
354 | |||
355 | if (info->state == PN544_ST_FW_READY) { | ||
356 | len = min(count, info->buflen); | ||
357 | |||
358 | mutex_lock(&info->read_mutex); | ||
359 | r = pn544_fw_read(info->i2c_dev, info->buf, len); | ||
360 | info->read_irq = PN544_NONE; | ||
361 | mutex_unlock(&info->read_mutex); | ||
362 | |||
363 | if (r < 0) { | ||
364 | dev_err(&info->i2c_dev->dev, "FW read failed: %d\n", r); | ||
365 | goto out; | ||
366 | } | ||
367 | |||
368 | print_hex_dump(KERN_DEBUG, "FW read: ", DUMP_PREFIX_NONE, | ||
369 | 16, 2, info->buf, r, false); | ||
370 | |||
371 | *offset += r; | ||
372 | if (copy_to_user(buf, info->buf, r)) { | ||
373 | r = -EFAULT; | ||
374 | goto out; | ||
375 | } | ||
376 | } else { | ||
377 | len = min(count, info->buflen); | ||
378 | |||
379 | mutex_lock(&info->read_mutex); | ||
380 | r = pn544_i2c_read(info->i2c_dev, info->buf, len); | ||
381 | info->read_irq = PN544_NONE; | ||
382 | mutex_unlock(&info->read_mutex); | ||
383 | |||
384 | if (r < 0) { | ||
385 | dev_err(&info->i2c_dev->dev, "read failed (%d)\n", r); | ||
386 | goto out; | ||
387 | } | ||
388 | print_hex_dump(KERN_DEBUG, "read: ", DUMP_PREFIX_NONE, | ||
389 | 16, 2, info->buf, r, false); | ||
390 | |||
391 | *offset += r; | ||
392 | if (copy_to_user(buf, info->buf, r)) { | ||
393 | r = -EFAULT; | ||
394 | goto out; | ||
395 | } | ||
396 | } | ||
397 | |||
398 | out: | ||
399 | mutex_unlock(&info->mutex); | ||
400 | |||
401 | return r; | ||
402 | } | ||
403 | |||
404 | static unsigned int pn544_poll(struct file *file, poll_table *wait) | ||
405 | { | ||
406 | struct pn544_info *info = container_of(file->private_data, | ||
407 | struct pn544_info, miscdev); | ||
408 | struct i2c_client *client = info->i2c_dev; | ||
409 | int r = 0; | ||
410 | |||
411 | dev_dbg(&client->dev, "%s: info: %p\n", __func__, info); | ||
412 | |||
413 | mutex_lock(&info->mutex); | ||
414 | |||
415 | if (info->state == PN544_ST_COLD) { | ||
416 | r = -ENODEV; | ||
417 | goto out; | ||
418 | } | ||
419 | |||
420 | poll_wait(file, &info->read_wait, wait); | ||
421 | |||
422 | if (pn544_irq_state(info) == PN544_INT) { | ||
423 | r = POLLIN | POLLRDNORM; | ||
424 | goto out; | ||
425 | } | ||
426 | out: | ||
427 | mutex_unlock(&info->mutex); | ||
428 | |||
429 | return r; | ||
430 | } | ||
431 | |||
432 | static ssize_t pn544_write(struct file *file, const char __user *buf, | ||
433 | size_t count, loff_t *ppos) | ||
434 | { | ||
435 | struct pn544_info *info = container_of(file->private_data, | ||
436 | struct pn544_info, miscdev); | ||
437 | struct i2c_client *client = info->i2c_dev; | ||
438 | ssize_t len; | ||
439 | int r; | ||
440 | |||
441 | dev_dbg(&client->dev, "%s: info: %p, count %zu\n", __func__, | ||
442 | info, count); | ||
443 | |||
444 | mutex_lock(&info->mutex); | ||
445 | |||
446 | if (info->state == PN544_ST_COLD) { | ||
447 | r = -ENODEV; | ||
448 | goto out; | ||
449 | } | ||
450 | |||
451 | /* | ||
452 | * XXX: should we detect rset-writes and clean possible | ||
453 | * read_irq state | ||
454 | */ | ||
455 | if (info->state == PN544_ST_FW_READY) { | ||
456 | size_t fw_len; | ||
457 | |||
458 | if (count < PN544_FW_HEADER_SIZE) { | ||
459 | r = -EINVAL; | ||
460 | goto out; | ||
461 | } | ||
462 | |||
463 | len = min(count, info->buflen); | ||
464 | if (copy_from_user(info->buf, buf, len)) { | ||
465 | r = -EFAULT; | ||
466 | goto out; | ||
467 | } | ||
468 | |||
469 | print_hex_dump(KERN_DEBUG, "FW write: ", DUMP_PREFIX_NONE, | ||
470 | 16, 2, info->buf, len, false); | ||
471 | |||
472 | fw_len = PN544_FW_HEADER_SIZE + (info->buf[1] << 8) + | ||
473 | info->buf[2]; | ||
474 | |||
475 | if (len > fw_len) /* 1 msg at a time */ | ||
476 | len = fw_len; | ||
477 | |||
478 | r = pn544_fw_write(info->i2c_dev, info->buf, len); | ||
479 | } else { | ||
480 | if (count < PN544_LLC_MIN_SIZE) { | ||
481 | r = -EINVAL; | ||
482 | goto out; | ||
483 | } | ||
484 | |||
485 | len = min(count, info->buflen); | ||
486 | if (copy_from_user(info->buf, buf, len)) { | ||
487 | r = -EFAULT; | ||
488 | goto out; | ||
489 | } | ||
490 | |||
491 | print_hex_dump(KERN_DEBUG, "write: ", DUMP_PREFIX_NONE, | ||
492 | 16, 2, info->buf, len, false); | ||
493 | |||
494 | if (len > (info->buf[0] + 1)) /* 1 msg at a time */ | ||
495 | len = info->buf[0] + 1; | ||
496 | |||
497 | r = pn544_i2c_write(info->i2c_dev, info->buf, len); | ||
498 | } | ||
499 | out: | ||
500 | mutex_unlock(&info->mutex); | ||
501 | |||
502 | return r; | ||
503 | |||
504 | } | ||
505 | |||
506 | static long pn544_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | ||
507 | { | ||
508 | struct pn544_info *info = container_of(file->private_data, | ||
509 | struct pn544_info, miscdev); | ||
510 | struct i2c_client *client = info->i2c_dev; | ||
511 | struct pn544_nfc_platform_data *pdata; | ||
512 | unsigned int val; | ||
513 | int r = 0; | ||
514 | |||
515 | dev_dbg(&client->dev, "%s: info: %p, cmd: 0x%x\n", __func__, info, cmd); | ||
516 | |||
517 | mutex_lock(&info->mutex); | ||
518 | |||
519 | if (info->state == PN544_ST_COLD) { | ||
520 | r = -ENODEV; | ||
521 | goto out; | ||
522 | } | ||
523 | |||
524 | pdata = info->i2c_dev->dev.platform_data; | ||
525 | switch (cmd) { | ||
526 | case PN544_GET_FW_MODE: | ||
527 | dev_dbg(&client->dev, "%s: PN544_GET_FW_MODE\n", __func__); | ||
528 | |||
529 | val = (info->state == PN544_ST_FW_READY); | ||
530 | if (copy_to_user((void __user *)arg, &val, sizeof(val))) { | ||
531 | r = -EFAULT; | ||
532 | goto out; | ||
533 | } | ||
534 | |||
535 | break; | ||
536 | |||
537 | case PN544_SET_FW_MODE: | ||
538 | dev_dbg(&client->dev, "%s: PN544_SET_FW_MODE\n", __func__); | ||
539 | |||
540 | if (copy_from_user(&val, (void __user *)arg, sizeof(val))) { | ||
541 | r = -EFAULT; | ||
542 | goto out; | ||
543 | } | ||
544 | |||
545 | if (val) { | ||
546 | if (info->state == PN544_ST_FW_READY) | ||
547 | break; | ||
548 | |||
549 | pn544_disable(info); | ||
550 | r = pn544_enable(info, FW_MODE); | ||
551 | if (r < 0) | ||
552 | goto out; | ||
553 | } else { | ||
554 | if (info->state == PN544_ST_READY) | ||
555 | break; | ||
556 | pn544_disable(info); | ||
557 | r = pn544_enable(info, HCI_MODE); | ||
558 | if (r < 0) | ||
559 | goto out; | ||
560 | } | ||
561 | file->f_pos = info->read_offset; | ||
562 | break; | ||
563 | |||
564 | case TCGETS: | ||
565 | dev_dbg(&client->dev, "%s: TCGETS\n", __func__); | ||
566 | |||
567 | r = -ENOIOCTLCMD; | ||
568 | break; | ||
569 | |||
570 | default: | ||
571 | dev_err(&client->dev, "Unknown ioctl 0x%x\n", cmd); | ||
572 | r = -ENOIOCTLCMD; | ||
573 | break; | ||
574 | } | ||
575 | |||
576 | out: | ||
577 | mutex_unlock(&info->mutex); | ||
578 | |||
579 | return r; | ||
580 | } | ||
581 | |||
582 | static int pn544_open(struct inode *inode, struct file *file) | ||
583 | { | ||
584 | struct pn544_info *info = container_of(file->private_data, | ||
585 | struct pn544_info, miscdev); | ||
586 | struct i2c_client *client = info->i2c_dev; | ||
587 | int r = 0; | ||
588 | |||
589 | dev_dbg(&client->dev, "%s: info: %p, client %p\n", __func__, | ||
590 | info, info->i2c_dev); | ||
591 | |||
592 | mutex_lock(&info->mutex); | ||
593 | |||
594 | /* | ||
595 | * Only 1 at a time. | ||
596 | * XXX: maybe user (counter) would work better | ||
597 | */ | ||
598 | if (info->state != PN544_ST_COLD) { | ||
599 | r = -EBUSY; | ||
600 | goto out; | ||
601 | } | ||
602 | |||
603 | file->f_pos = info->read_offset; | ||
604 | r = pn544_enable(info, HCI_MODE); | ||
605 | |||
606 | out: | ||
607 | mutex_unlock(&info->mutex); | ||
608 | return r; | ||
609 | } | ||
610 | |||
611 | static int pn544_close(struct inode *inode, struct file *file) | ||
612 | { | ||
613 | struct pn544_info *info = container_of(file->private_data, | ||
614 | struct pn544_info, miscdev); | ||
615 | struct i2c_client *client = info->i2c_dev; | ||
616 | |||
617 | dev_dbg(&client->dev, "%s: info: %p, client %p\n", | ||
618 | __func__, info, info->i2c_dev); | ||
619 | |||
620 | mutex_lock(&info->mutex); | ||
621 | pn544_disable(info); | ||
622 | mutex_unlock(&info->mutex); | ||
623 | |||
624 | return 0; | ||
625 | } | ||
626 | |||
627 | static const struct file_operations pn544_fops = { | ||
628 | .owner = THIS_MODULE, | ||
629 | .llseek = no_llseek, | ||
630 | .read = pn544_read, | ||
631 | .write = pn544_write, | ||
632 | .poll = pn544_poll, | ||
633 | .open = pn544_open, | ||
634 | .release = pn544_close, | ||
635 | .unlocked_ioctl = pn544_ioctl, | ||
636 | }; | ||
637 | |||
638 | #ifdef CONFIG_PM | ||
639 | static int pn544_suspend(struct device *dev) | ||
640 | { | ||
641 | struct i2c_client *client = to_i2c_client(dev); | ||
642 | struct pn544_info *info; | ||
643 | int r = 0; | ||
644 | |||
645 | dev_info(&client->dev, "***\n%s: client %p\n***\n", __func__, client); | ||
646 | |||
647 | info = i2c_get_clientdata(client); | ||
648 | dev_info(&client->dev, "%s: info: %p, client %p\n", __func__, | ||
649 | info, client); | ||
650 | |||
651 | mutex_lock(&info->mutex); | ||
652 | |||
653 | switch (info->state) { | ||
654 | case PN544_ST_FW_READY: | ||
655 | /* Do not suspend while upgrading FW, please! */ | ||
656 | r = -EPERM; | ||
657 | break; | ||
658 | |||
659 | case PN544_ST_READY: | ||
660 | /* | ||
661 | * CHECK: Device should be in standby-mode. No way to check? | ||
662 | * Allowing low power mode for the regulator is potentially | ||
663 | * dangerous if pn544 does not go to suspension. | ||
664 | */ | ||
665 | break; | ||
666 | |||
667 | case PN544_ST_COLD: | ||
668 | break; | ||
669 | }; | ||
670 | |||
671 | mutex_unlock(&info->mutex); | ||
672 | return r; | ||
673 | } | ||
674 | |||
675 | static int pn544_resume(struct device *dev) | ||
676 | { | ||
677 | struct i2c_client *client = to_i2c_client(dev); | ||
678 | struct pn544_info *info = i2c_get_clientdata(client); | ||
679 | int r = 0; | ||
680 | |||
681 | dev_dbg(&client->dev, "%s: info: %p, client %p\n", __func__, | ||
682 | info, client); | ||
683 | |||
684 | mutex_lock(&info->mutex); | ||
685 | |||
686 | switch (info->state) { | ||
687 | case PN544_ST_READY: | ||
688 | /* | ||
689 | * CHECK: If regulator low power mode is allowed in | ||
690 | * pn544_suspend, we should go back to normal mode | ||
691 | * here. | ||
692 | */ | ||
693 | break; | ||
694 | |||
695 | case PN544_ST_COLD: | ||
696 | break; | ||
697 | |||
698 | case PN544_ST_FW_READY: | ||
699 | break; | ||
700 | }; | ||
701 | |||
702 | mutex_unlock(&info->mutex); | ||
703 | |||
704 | return r; | ||
705 | } | ||
706 | |||
707 | static SIMPLE_DEV_PM_OPS(pn544_pm_ops, pn544_suspend, pn544_resume); | ||
708 | #endif | ||
709 | |||
710 | static struct device_attribute pn544_attr = | ||
711 | __ATTR(nfc_test, S_IRUGO, pn544_test, NULL); | ||
712 | |||
713 | static int __devinit pn544_probe(struct i2c_client *client, | ||
714 | const struct i2c_device_id *id) | ||
715 | { | ||
716 | struct pn544_info *info; | ||
717 | struct pn544_nfc_platform_data *pdata; | ||
718 | int r = 0; | ||
719 | |||
720 | dev_dbg(&client->dev, "%s\n", __func__); | ||
721 | dev_dbg(&client->dev, "IRQ: %d\n", client->irq); | ||
722 | |||
723 | /* private data allocation */ | ||
724 | info = kzalloc(sizeof(struct pn544_info), GFP_KERNEL); | ||
725 | if (!info) { | ||
726 | dev_err(&client->dev, | ||
727 | "Cannot allocate memory for pn544_info.\n"); | ||
728 | r = -ENOMEM; | ||
729 | goto err_info_alloc; | ||
730 | } | ||
731 | |||
732 | info->buflen = max(PN544_MSG_MAX_SIZE, PN544_MAX_I2C_TRANSFER); | ||
733 | info->buf = kzalloc(info->buflen, GFP_KERNEL); | ||
734 | if (!info->buf) { | ||
735 | dev_err(&client->dev, | ||
736 | "Cannot allocate memory for pn544_info->buf.\n"); | ||
737 | r = -ENOMEM; | ||
738 | goto err_buf_alloc; | ||
739 | } | ||
740 | |||
741 | info->regs[0].supply = reg_vdd_io; | ||
742 | info->regs[1].supply = reg_vbat; | ||
743 | r = regulator_bulk_get(&client->dev, ARRAY_SIZE(info->regs), | ||
744 | info->regs); | ||
745 | if (r < 0) | ||
746 | goto err_kmalloc; | ||
747 | |||
748 | info->i2c_dev = client; | ||
749 | info->state = PN544_ST_COLD; | ||
750 | info->read_irq = PN544_NONE; | ||
751 | mutex_init(&info->read_mutex); | ||
752 | mutex_init(&info->mutex); | ||
753 | init_waitqueue_head(&info->read_wait); | ||
754 | i2c_set_clientdata(client, info); | ||
755 | pdata = client->dev.platform_data; | ||
756 | if (!pdata) { | ||
757 | dev_err(&client->dev, "No platform data\n"); | ||
758 | r = -EINVAL; | ||
759 | goto err_reg; | ||
760 | } | ||
761 | |||
762 | if (!pdata->request_resources) { | ||
763 | dev_err(&client->dev, "request_resources() missing\n"); | ||
764 | r = -EINVAL; | ||
765 | goto err_reg; | ||
766 | } | ||
767 | |||
768 | r = pdata->request_resources(client); | ||
769 | if (r) { | ||
770 | dev_err(&client->dev, "Cannot get platform resources\n"); | ||
771 | goto err_reg; | ||
772 | } | ||
773 | |||
774 | r = request_threaded_irq(client->irq, NULL, pn544_irq_thread_fn, | ||
775 | IRQF_TRIGGER_RISING, PN544_DRIVER_NAME, | ||
776 | info); | ||
777 | if (r < 0) { | ||
778 | dev_err(&client->dev, "Unable to register IRQ handler\n"); | ||
779 | goto err_res; | ||
780 | } | ||
781 | |||
782 | /* If we don't have the test we don't need the sysfs file */ | ||
783 | if (pdata->test) { | ||
784 | r = device_create_file(&client->dev, &pn544_attr); | ||
785 | if (r) { | ||
786 | dev_err(&client->dev, | ||
787 | "sysfs registration failed, error %d\n", r); | ||
788 | goto err_irq; | ||
789 | } | ||
790 | } | ||
791 | |||
792 | info->miscdev.minor = MISC_DYNAMIC_MINOR; | ||
793 | info->miscdev.name = PN544_DRIVER_NAME; | ||
794 | info->miscdev.fops = &pn544_fops; | ||
795 | info->miscdev.parent = &client->dev; | ||
796 | r = misc_register(&info->miscdev); | ||
797 | if (r < 0) { | ||
798 | dev_err(&client->dev, "Device registration failed\n"); | ||
799 | goto err_sysfs; | ||
800 | } | ||
801 | |||
802 | dev_dbg(&client->dev, "%s: info: %p, pdata %p, client %p\n", | ||
803 | __func__, info, pdata, client); | ||
804 | |||
805 | return 0; | ||
806 | |||
807 | err_sysfs: | ||
808 | if (pdata->test) | ||
809 | device_remove_file(&client->dev, &pn544_attr); | ||
810 | err_irq: | ||
811 | free_irq(client->irq, info); | ||
812 | err_res: | ||
813 | if (pdata->free_resources) | ||
814 | pdata->free_resources(); | ||
815 | err_reg: | ||
816 | regulator_bulk_free(ARRAY_SIZE(info->regs), info->regs); | ||
817 | err_kmalloc: | ||
818 | kfree(info->buf); | ||
819 | err_buf_alloc: | ||
820 | kfree(info); | ||
821 | err_info_alloc: | ||
822 | return r; | ||
823 | } | ||
824 | |||
825 | static __devexit int pn544_remove(struct i2c_client *client) | ||
826 | { | ||
827 | struct pn544_info *info = i2c_get_clientdata(client); | ||
828 | struct pn544_nfc_platform_data *pdata = client->dev.platform_data; | ||
829 | |||
830 | dev_dbg(&client->dev, "%s\n", __func__); | ||
831 | |||
832 | misc_deregister(&info->miscdev); | ||
833 | if (pdata->test) | ||
834 | device_remove_file(&client->dev, &pn544_attr); | ||
835 | |||
836 | if (info->state != PN544_ST_COLD) { | ||
837 | if (pdata->disable) | ||
838 | pdata->disable(); | ||
839 | |||
840 | info->read_irq = PN544_NONE; | ||
841 | } | ||
842 | |||
843 | free_irq(client->irq, info); | ||
844 | if (pdata->free_resources) | ||
845 | pdata->free_resources(); | ||
846 | |||
847 | regulator_bulk_free(ARRAY_SIZE(info->regs), info->regs); | ||
848 | kfree(info->buf); | ||
849 | kfree(info); | ||
850 | |||
851 | return 0; | ||
852 | } | ||
853 | |||
854 | static struct i2c_driver pn544_driver = { | ||
855 | .driver = { | ||
856 | .name = PN544_DRIVER_NAME, | ||
857 | #ifdef CONFIG_PM | ||
858 | .pm = &pn544_pm_ops, | ||
859 | #endif | ||
860 | }, | ||
861 | .probe = pn544_probe, | ||
862 | .id_table = pn544_id_table, | ||
863 | .remove = __devexit_p(pn544_remove), | ||
864 | }; | ||
865 | |||
866 | static int __init pn544_init(void) | ||
867 | { | ||
868 | int r; | ||
869 | |||
870 | pr_debug(DRIVER_DESC ": %s\n", __func__); | ||
871 | |||
872 | r = i2c_add_driver(&pn544_driver); | ||
873 | if (r) { | ||
874 | pr_err(PN544_DRIVER_NAME ": driver registration failed\n"); | ||
875 | return r; | ||
876 | } | ||
877 | |||
878 | return 0; | ||
879 | } | ||
880 | |||
881 | static void __exit pn544_exit(void) | ||
882 | { | ||
883 | i2c_del_driver(&pn544_driver); | ||
884 | pr_info(DRIVER_DESC ", Exiting.\n"); | ||
885 | } | ||
886 | |||
887 | module_init(pn544_init); | ||
888 | module_exit(pn544_exit); | ||
889 | |||
890 | MODULE_LICENSE("GPL"); | ||
891 | MODULE_DESCRIPTION(DRIVER_DESC); | ||