5\- uo /*
[|u^:&az * Driver for the PN544 NFC chip.
(
?V`|[+u *
)s2] -n}W * Copyright (C) Nokia Corporation
TOYK'|lwM *
]Z JoC!u * Author: Jari Vanhala <
ext-jari.vanhala@nokia.com>
P:qmg"i@3 * Contact: Matti Aaltonen <
matti.j.aaltonen@nokia.com>
LSo!_tY *
8s%/5v" * This program is free software; you can redistribute it and/or
X|M!Nt0' * modify it under the terms of the GNU General Public License
~xH&"1 * version 2 as published by the Free Software Foundation.
15$xa_w}L
*
"q4tvcK. * This program is distributed in the hope that it will be useful,
BG{f)2F\ * but WITHOUT ANY WARRANTY; without even the implied warranty of
!,J#
r * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
bQll;U^A * GNU General Public License for more details.
GN.Oa$ *
eE;tiX/ * You should have received a copy of the GNU General Public License
W+nu=iQ! * along with this program; if not, write to the Free Software
l{3B}_, * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
J(
}2Ua_ */
<Ox[![SR MfTLa)Rz #include <linux/completion.h>
LHAlXo; #include <linux/crc-ccitt.h>
y!e]bvN #include <linux/delay.h>
Ae)xFnuq3 #include <linux/interrupt.h>
E$d3+`` #include <linux/kernel.h>
R{hX--|j #include <linux/miscdevice.h>
&[.5@sv #include <linux/module.h>
gU9{~-9} #include <linux/mutex.h>
0oe<=L]F #include <linux/nfc/pn544.h>
]AP1+
&9fN #include <linux/poll.h>
I Mgd2qIC #include <linux/regulator/consumer.h>
NOz3_k #include <linux/serial_core.h> /* for TCGETS */
8WP>u8& #include <linux/slab.h>
>&L|oq7$ IS C.~q2 #define DRIVER_CARD "PN544 NFC"
oL4W>b ) #define DRIVER_DESC "NFC driver for PN544"
]!UYl H/8^Fvd static struct i2c_device_id pn544_id_table[] = {
h@)U,& { PN544_DRIVER_NAME, 0 },
-"(*'hD { }
y)f.ON36I };
myx/ |-V"F MODULE_DEVICE_TABLE(i2c, pn544_id_table);
q:{#kv8 ,RP-)j"Wff #define HCI_MODE 0
R^Rc!G} #define FW_MODE 1
NgNGq\! T.q2tC[bR enum pn544_state {
?}||?2=P PN544_ST_COLD,
Re%[t9F& PN544_ST_FW_READY,
vr!J3H f PN544_ST_READY,
[f6uwp };
5'lVh/ S"Al[{ enum pn544_irq {
h\RX/C!+ PN544_NONE,
pjl%Jm PN544_INT,
2 a<\4w' };
&|SWy
2N =;Id["+ struct pn544_info {
EZtU6kW" struct miscdevice miscdev;
7KT*p&xm struct i2c_client *i2c_dev;
6fwNlC/9 struct regulator_bulk_data regs[3];
yUoR6w J?4{#p enum pn544_state state;
vz^ ] g wait_queue_head_t read_wait;
e8a^"Z`a loff_t read_offset;
9t! d.} enum pn544_irq read_irq;
j:9M${~ struct mutex read_mutex; /* Serialize read_irq access */
Iil2R}1 struct mutex mutex; /* Serialize info struct access */
Xz]l#w4Pp u8 *buf;
c
'|*{%<e2 size_t buflen;
_h%Jf{nu };
.Xg.,kW Sn:>|y~ static const char reg_vdd_io[] = "Vdd_IO";
0AZ9I!&i static const char reg_vbat[] = "VBat";
KbJ6U75|f static const char reg_vsim[] = "VSim";
w+$$uz .5JIQWE( /* sysfs interface */
8jK=A2pTa static ssize_t pn544_test(struct device *dev,
,%i
Scr,z struct device_attribute *attr, char *buf)
2g(_Kdj*{ {
#%,X),%- struct pn544_info *info = dev_get_drvdata(dev);
S)CsH1Q struct i2c_client *client = info->i2c_dev;
"+DA)K struct pn544_nfc_platform_data *pdata = client->dev.platform_data;
B=Hd:P| Z'o0::k return snprintf(buf, PAGE_SIZE, "%d\n", pdata->test());
g 2Fg }
$-_" SWG. z zG=!JR static int pn544_enable(struct pn544_info *info, int mode)
7uBx {
#83 struct pn544_nfc_platform_data *pdata;
h'ik3mLH struct i2c_client *client = info->i2c_dev;
-:}vf? Q\oa<R
D5 int r;
N$=YL
@m8 =^"Sx??V r = regulator_bulk_enable(ARRAY_SIZE(info->regs), info->regs);
KFM[caKeJO if (r < 0)
iGW(2.Z return r;
!~^2Mu(X cGot0' mB pdata = client->dev.platform_data;
s/1r{;q info->read_irq = PN544_NONE;
=lNW1J\SW if (pdata->enable)
@Z]0c=-+ pdata->enable(mode);
s>9I#_4] :?f<tNU$ if (mode) {
`&;#A*C0 info->state = PN544_ST_FW_READY;
@6UY4vq9 dev_dbg(&client->dev, "now in FW-mode\n");
O:]']' / } else {
;NP-tA) info->state = PN544_ST_READY;
<I,4Kc! dev_dbg(&client->dev, "now in HCI-mode\n");
A;!5c;ftj, }
?Ld),A/c >^8O :. usleep_range(10000, 15000);
Rsx6vF8]5 O"9t,B>=i return 0;
g5BL"Dn }
j;$f[@0o }0~$^J static void pn544_disable(struct pn544_info *info)
s'O%@/;J {
-J]?M struct pn544_nfc_platform_data *pdata;
W83d$4\d struct i2c_client *client = info->i2c_dev;
a$W
O}g? piIZ*@' pdata = client->dev.platform_data;
XT0-"-q if (pdata->disable)
RXRbW %b pdata->disable();
j)ic7b 1@Ba7>%' info->state = PN544_ST_COLD;
dcKpsX c((3 B dev_dbg(&client->dev, "Now in OFF-mode\n");
%+r(*Q+0$f NbWEP\dS'z msleep(PN544_RESETVEN_TIME);
$`xpn#lz ~HY)$Yp; info->read_irq = PN544_NONE;
k(f),_ regulator_bulk_disable(ARRAY_SIZE(info->regs), info->regs);
i7RK*{ }
n3e,vP? R e"@r[pq-{u static int check_crc(u8 *buf, int buflen)
qJ" (:~ {
=K@LEZZ'/< u8 len;
l_yy;e u16 crc;
X8}r= K~ ->#wDL!6 len = buf[0] + 1;
%>&~?zrq if (len < 4 || len != buflen || len > PN544_MSG_MAX_SIZE) {
:M6|V_Yp pr_err(PN544_DRIVER_NAME
Y1o[|ytW ": CRC; corrupt packet len %u (%d)\n", len, buflen);
Rd(8j+Q?ps print_hex_dump(KERN_DEBUG, "crc: ", DUMP_PREFIX_NONE,
hLfWDf*T| 16, 2, buf, buflen, false);
r6j[C"@ return -EPERM;
P]"@3Z&w }
W3l[a^1d crc = crc_ccitt(0xffff, buf, len - 2);
9#H0|zL crc = ~crc;
+sJ{9# 6 tE>FL if (buf[len-2] != (crc & 0xff) || buf[len-1] != (crc >> 8)) {
-raK pr_err(PN544_DRIVER_NAME ": CRC error 0x%x != 0x%x 0x%x\n",
Q3=X#FQ crc, buf[len-1], buf[len-2]);
+R?E @S `LH 9@Z{ print_hex_dump(KERN_DEBUG, "crc: ", DUMP_PREFIX_NONE,
^uX"04>; 16, 2, buf, buflen, false);
K*^'tltJ return -EPERM;
DN9x<%/- }
d%@0xsU1 return 0;
"eoPG#]& }
/XG7M=A$o wz+mFf static int pn544_i2c_write(struct i2c_client *client, u8 *buf, int len)
2SU'lh\E {
n4?;!p<F int r;
h-.^*=]R6 |
{zka.sJ
if (len < 4 || len != (buf[0] + 1)) {
.aL%}`8l? dev_err(&client->dev, "%s: Illegal message length: %d\n",
D}%VZA}]. __func__, len);
; 8VZsh return -EINVAL;
oCwep^P(v }
$_% r:xg#&"* if (check_crc(buf, len))
)YCH>Za return -EINVAL;
D _\HX9 ,>g(%3C usleep_range(3000, 6000);
0?R$>=u Uq=Rz8hLM r = i2c_master_send(client, buf, len);
.yzXw8~S dev_dbg(&client->dev, "send: %d\n", r);
(*26aMp Yy!G?>hC if (r == -EREMOTEIO) { /* Retry, chip was in standby */
_2k<MiqCD[ usleep_range(6000, 10000);
b5p;)# r = i2c_master_send(client, buf, len);
$sL+k 'dY dev_dbg(&client->dev, "send2: %d\n", r);
>yyu:dk-; }
.&=\
*cZc
-vT$UP if (r != len)
7F~Jz*,B*W return -EREMOTEIO;
qq^[(n M#o=., return r;
84(jg P }
^')4RU Pi&\GMzd static int pn544_i2c_read(struct i2c_client *client, u8 *buf, int buflen)
F&/}x15 {
{YzpYc1
int r;
11J:>A5zt u8 len;
G*v,-O kSJ:4! lFU /*
Rlr[uU_ * You could read a packet in one go, but then you'd need to read
3,+UsB% * max size and rest would be 0xff fill, so we do split reads.
$YBH;^# */
Xp^>SSt:4 r = i2c_master_recv(client, &len, 1);
)sEAPIka dev_dbg(&client->dev, "recv1: %d\n", r);
-r_ Pp}s ZDrTPnA[ if (r != 1)
Erl@]P4 return -EREMOTEIO;
.b%mr:nEt7 !OH'pC5 if (len < PN544_LLC_HCI_OVERHEAD)
^w
RD| len = PN544_LLC_HCI_OVERHEAD;
YkV-]%c else if (len > (PN544_MSG_MAX_SIZE - 1))
.|ZnU]~T len = PN544_MSG_MAX_SIZE - 1;
ht)KS9Xu ]o8~b- if (1 + len > buflen) /* len+(data+crc16) */
@0:mP return -EMSGSIZE;
x(zW<J5X" avv/mEf-f buf[0] = len;
^q~.5c| YAF0I%PYU r = i2c_master_recv(client, buf + 1, len);
?y{"OuRf. dev_dbg(&client->dev, "recv2: %d\n", r);
c_2kHT
,wra f#UdP if (r != len)
r,Pu-bhF return -EREMOTEIO;
HLt;1:b 5.)/gK2$ usleep_range(3000, 6000);
Lop=._W Kib?JRYt return r + 1;
rNHV }
"_&HM4%! Sytx9`G 5 static int pn544_fw_write(struct i2c_client *client, u8 *buf, int len)
w*N9p8hb] {
"2/VDB4!FG int r;
_nnl+S>K LYiz:cQh dev_dbg(&client->dev, "%s\n", __func__);
j#XU\G |c>A3 P$=B if (len < PN544_FW_HEADER_SIZE ||
Y6@A@VJ (PN544_FW_HEADER_SIZE + (buf[1] << 8) + buf[2]) != len)
}oTac return -EINVAL;
">RDa<H] 'uOp?g' 7 r = i2c_master_send(client, buf, len);
3?(||h{ dev_dbg(&client->dev, "fw send: %d\n", r);
D&)gcO`\ )%OV|\5# if (r == -EREMOTEIO) { /* Retry, chip was in standby */
4B8{\"6 usleep_range(6000, 10000);
sXSZ#@u,WN r = i2c_master_send(client, buf, len);
I-q@@!= dev_dbg(&client->dev, "fw send2: %d\n", r);
SY2B\TV }
{z%%(,I cYTX)]^u if (r != len)
/SD2e@x{U return -EREMOTEIO;
aI8K*D )@ K`1\3J) return r;
yyHr. C }
BO ^T
: Xl%&hM static int pn544_fw_read(struct i2c_client *client, u8 *buf, int buflen)
tL4xHa6v] {
4d3PF`,H` int r, len;
(sn|`k3I *%cI,}% if (buflen < PN544_FW_HEADER_SIZE)
ji2if.t@ return -EINVAL;
j:,*Liz $wVY)p9Q r = i2c_master_recv(client, buf, PN544_FW_HEADER_SIZE);
A!
1> dev_dbg(&client->dev, "FW recv1: %d\n", r);
Hp":r%) mvxg|< if (r < 0)
: C;=<$ return r;
Kc\0-3 Z EY!aiH6P if (r < PN544_FW_HEADER_SIZE)
413r3/ return -EINVAL;
T ,gMc BiHBu8< len = (buf[1] << 8) + buf[2];
rC<m6 if (len == 0) /* just header, no additional data */
p2y
h return r;
s\Cl3 ? P`]^# if (len > buflen - PN544_FW_HEADER_SIZE)
D1lHq/ return -EMSGSIZE;
37!}8 gy<pN?Mw r = i2c_master_recv(client, buf + PN544_FW_HEADER_SIZE, len);
c-avX dev_dbg(&client->dev, "fw recv2: %d\n", r);
2Sb~tTGz79 Q_1EAxt if (r != len)
}` return -EINVAL;
&ze'V
, : Z!|nc. return r + PN544_FW_HEADER_SIZE;
12E@9s$Z }
W?R$+~G D9c8#k9Y. static irqreturn_t pn544_irq_thread_fn(int irq, void *dev_id)
Mi'eViH {
e[n T'e struct pn544_info *info = dev_id;
z/rN+ , struct i2c_client *client = info->i2c_dev;
bU:"dqRm< :d!.E$S BUG_ON(!info);
Khw!+!(H BUG_ON(irq != info->i2c_dev->irq);
Ctt{j'-[ x_(B7ob dev_dbg(&client->dev, "IRQ\n");
g >-iBxml Ra_6}k mutex_lock(&info->read_mutex);
.Fh5:WN info->read_irq = PN544_INT;
vC J mutex_unlock(&info->read_mutex);
X'[SCs l=EIbh wake_up_interruptible(&info->read_wait);
'1r:z, o| S)$ES6]9/ return IRQ_HANDLED;
iQin|$F_O }
+5);"71 0R* static enum pn544_irq pn544_irq_state(struct pn544_info *info)
~"}-cl, {
l!q i:H<=1 enum pn544_irq irq;
oOe5IczS( AytHnp\H mutex_lock(&info->read_mutex);
R0\E?9P irq = info->read_irq;
S <|e/![@ mutex_unlock(&info->read_mutex);
Ty#L%k}-t /*
le|e 4f*+ * XXX: should we check GPIO-line status directly?
RpS'Tz} * return pdata->irq_status() ? PN544_INT : PN544_NONE;
}e9:2 */
O-bC+vB]M ga~rllm;i return irq;
+l&ZN\@0X }
o $p*C MF]s(7U4` static ssize_t pn544_read(struct file *file, char __user *buf,
q^goi1 size_t count, loff_t *offset)
[Fr.ik {
M_UhFY=' struct pn544_info *info = container_of(file->private_data,
+&-/$\" struct pn544_info, miscdev);
S1;#58 struct i2c_client *client = info->i2c_dev;
`2d ,=.X enum pn544_irq irq;
Ck(D:
% ~s size_t len;
Gv6EJV1i int r = 0;
SH5GW3\h 6#.z:_ dev_dbg(&client->dev, "%s: info: %p, count: %zu\n", __func__,
zn>*^h0B info, count);
Uq0RJ<n . v0 .wG mutex_lock(&info->mutex);
SAc}5. 3(}HD*{E[@ if (info->state == PN544_ST_COLD) {
Nm:nSqc r = -ENODEV;
pvP|.sw5G goto out;
x(5>f9b b }
qS|bpC0x Y*B}^!k6 irq = pn544_irq_state(info);
zpiqJEf|'" if (irq == PN544_NONE) {
N
0&h5 if (file->f_flags & O_NONBLOCK) {
.0cm
mpUNq r = -EAGAIN;
"f(iQI goto out;
q%"]}@a0 }
'1|r+(q|2 \ d+&&ns if (wait_event_interruptible(info->read_wait,
.& B_\* (info->read_irq == PN544_INT))) {
Qp!r_a&
r = -ERESTARTSYS;
oAA%pZ@ goto out;
Pfe&wA't }
$2
~RZpS }
d9sl(;r e
,k,L if (info->state == PN544_ST_FW_READY) {
,57g_z]V len = min(count, info->buflen);
QOcB ]G 'kL>F&| mutex_lock(&info->read_mutex);
kf~ D m}bV r = pn544_fw_read(info->i2c_dev, info->buf, len);
2Do^N5y info->read_irq = PN544_NONE;
iO,0Sb
<y mutex_unlock(&info->read_mutex);
=sPY+~<o /^
hB6_'D if (r < 0) {
4[9~g=y> dev_err(&info->i2c_dev->dev, "FW read failed: %d\n", r);
|\*7J!Liv goto out;
a7)q^;:O }
Ma:xxsH. mfIY7DP print_hex_dump(KERN_DEBUG, "FW read: ", DUMP_PREFIX_NONE,
$e_A( | 16, 2, info->buf, r, false);
="P3TP T8JM4F *offset += r;
KFkKr>S: if (copy_to_user(buf, info->buf, r)) {
5<<e_n.2q r = -EFAULT;
\vs,$h goto out;
Uz>5!_ }
fF;Oz"I{\ } else {
-z-58FLlO len = min(count, info->buflen);
L L7a20 ~Wm`SIV mutex_lock(&info->read_mutex);
dMp7 ,{FhF r = pn544_i2c_read(info->i2c_dev, info->buf, len);
u7UqN info->read_irq = PN544_NONE;
M6jP>fbV* mutex_unlock(&info->read_mutex);
cH.T6u_% =4/LixsV| if (r < 0) {
0e^j :~* dev_err(&info->i2c_dev->dev, "read failed (%d)\n", r);
#)AcK|*y goto out;
ZsirX~W< }
p^Kp= z print_hex_dump(KERN_DEBUG, "read: ", DUMP_PREFIX_NONE,
)**k3u
t4 16, 2, info->buf, r, false);
8 *;G\$+ :CV!:sUm *offset += r;
wciYv, if (copy_to_user(buf, info->buf, r)) {
c BQ|mA r = -EFAULT;
S)p{4`p% goto out;
{:$0j|zL1 }
IpXg2QbN }
;``*]tY$ 4tz8^z[Kw out:
GrGgR7eC#P mutex_unlock(&info->mutex);
JUok@6 ;_R;P;< return r;
&THM]3: }
J6;^:() IJ3[6>/M0 static unsigned int pn544_poll(struct file *file, poll_table *wait)
L01R.3Z+ {
B08q/qi struct pn544_info *info = container_of(file->private_data,
_-H uO/ struct pn544_info, miscdev);
!T@>Ld: struct i2c_client *client = info->i2c_dev;
-@b&qi7&S int r = 0;
'm# -)R! >|KfO> dev_dbg(&client->dev, "%s: info: %p\n", __func__, info);
5m&{f>]T U5jY/e_ mutex_lock(&info->mutex);
M@UkXA} ^QTl (L if (info->state == PN544_ST_COLD) {
(k"|k r = -ENODEV;
ELeR5xT goto out;
_tS<\zy@y }
eC%.xu^ '
jR8 3A* poll_wait(file, &info->read_wait, wait);
6C9KT;6 Jxi>1 if (pn544_irq_state(info) == PN544_INT) {
=<s+cM r = POLLIN | POLLRDNORM;
7Av/ZS goto out;
W%hdS<b }
l]Jk
}. out:
2f] :n mutex_unlock(&info->mutex);
"tBdz V TKvUBy return r;
3M8P% }
x-:vpv%6y UTc$zc7 static ssize_t pn544_write(struct file *file, const char __user *buf,
X0^gj>GI| size_t count, loff_t *ppos)
4JKB6~Y {
-v8Jn#f struct pn544_info *info = container_of(file->private_data,
Gy.<gyK9 struct pn544_info, miscdev);
[4]lAxrRF struct i2c_client *client = info->i2c_dev;
)TJz'J\* ssize_t len;
H@bra~k- int r;
.+]e9mV s@OCj0'l dev_dbg(&client->dev, "%s: info: %p, count %zu\n", __func__,
qEX2K^y'4" info, count);
GeWB"(t >~_y\ mutex_lock(&info->mutex);
quN7'5ZC[ N{46DS if (info->state == PN544_ST_COLD) {
ZZA!Y9ia2 r = -ENODEV;
\v44 Vmfz goto out;
d*,% -Io }
kV!0cLH!hH \)eHf
7H
/*
( t#w@< * XXX: should we detect rset-writes and clean possible
4*&x% ~* * read_irq state
A@bWlwfl */
SJoQaR,)> if (info->state == PN544_ST_FW_READY) {
{/uBZ( size_t fw_len;
n{d}]V@ d#Sc4xuf if (count < PN544_FW_HEADER_SIZE) {
q@F"fjWBr r = -EINVAL;
>&TSz5Q goto out;
Y;6<AIx> }
`J[(Dx'y=t A^q= :ofQ len = min(count, info->buflen);
OOQfa#~k if (copy_from_user(info->buf, buf, len)) {
@ \J R xJ r = -EFAULT;
kFgN^v^t goto out;
[q cT?h }
E:V&:9aQ@ @g9j+DcU print_hex_dump(KERN_DEBUG, "FW write: ", DUMP_PREFIX_NONE,
7J~6J.m 16, 2, info->buf, len, false);
.{k(4_Q?I H$KE*Wwq fw_len = PN544_FW_HEADER_SIZE + (info->buf[1] << 8) +
\ 3n{%\_ info->buf[2];
leiED' </t_<I0{ if (len > fw_len) /* 1 msg at a time */
E$.|h;i]Q len = fw_len;
FH)bE#4 p|,K2^?Y r = pn544_fw_write(info->i2c_dev, info->buf, len);
*h1Zqb } else {
$5GvF1 if (count < PN544_LLC_MIN_SIZE) {
GC66n1- X r = -EINVAL;
}r]WB)_w goto out;
hghtF }
cBmo#:>' bv9\Jp0c len = min(count, info->buflen);
aQCbRS6 if (copy_from_user(info->buf, buf, len)) {
&UP@Sr0D7 r = -EFAULT;
,
M /-lW goto out;
{*~aVw {k }
4D"IAI [@kzC/Jq3 print_hex_dump(KERN_DEBUG, "write: ", DUMP_PREFIX_NONE,
iN*d84KTP 16, 2, info->buf, len, false);
_Jk-nZgn =}\]i* if (len > (info->buf[0] + 1)) /* 1 msg at a time */
w4'(Y,(` len = info->buf[0] + 1;
-le:0NUwI ^8.R 'Yq r = pn544_i2c_write(info->i2c_dev, info->buf, len);
$}TqBBe }
TUJ]u2J8? out:
D4s*J21)D mutex_unlock(&info->mutex);
?Ee?Ol?i2 'Vy$d<@s[ return r;
fbB(WE+ *u>2" !+Ob }
{5.,gb @6 j_&/^-;e static long pn544_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
^4Tr
@g#]" {
C+P}R]cT" struct pn544_info *info = container_of(file->private_data,
R"5/ struct pn544_info, miscdev);
si=/=h struct i2c_client *client = info->i2c_dev;
:|<D(YA struct pn544_nfc_platform_data *pdata;
TMKemci unsigned int val;
EYGJDv(S int r = 0;
sa#=#0yg *Zt)J8C dev_dbg(&client->dev, "%s: info: %p, cmd: 0x%x\n", __func__, info, cmd);
\b.2f+;3 < t>N(e mutex_lock(&info->mutex);
hz Vpv,|G 1kio.9NIp if (info->state == PN544_ST_COLD) {
lADi r = -ENODEV;
rMe`HM@ goto out;
&BG^:4b }
m{pL<
g^M g.DgJX&i pdata = info->i2c_dev->dev.platform_data;
,U>g LTS switch (cmd) {
)K@ 20Q+0K case PN544_GET_FW_MODE:
>+u5%5-wr dev_dbg(&client->dev, "%s: PN544_GET_FW_MODE\n", __func__);
Bf1GHnXv s]L`&fY]O val = (info->state == PN544_ST_FW_READY);
`U2PlCf| if (copy_to_user((void __user *)arg, &val, sizeof(val))) {
TUy*wp9 r = -EFAULT;
lxbbyy25 goto out;
\5s!lv*& }
F__DPEAc_ s<:"rw` break;
FX}<F0([? 8x58sOR= case PN544_SET_FW_MODE:
MuZ\<;W$ dev_dbg(&client->dev, "%s: PN544_SET_FW_MODE\n", __func__);
umrRlF4M; ed{z^!w4 if (copy_from_user(&val, (void __user *)arg, sizeof(val))) {
KT?vs5jg$& r = -EFAULT;
L4Nk+R; goto out;
eqeVz` }
> %#J8 LE1&atq if (val) {
z+wV(i97 if (info->state == PN544_ST_FW_READY)
0R_ZP12 break;
HP]Xh~aP ,:>>04O pn544_disable(info);
gjo\gP@ r = pn544_enable(info, FW_MODE);
jq.@<<j|$ if (r < 0)
]d$)G4X1 goto out;
JFYeOmR+l } else {
~p'/Z@Atu if (info->state == PN544_ST_READY)
$|(roC( break;
.]r[0U pn544_disable(info);
{zVJlJKxs r = pn544_enable(info, HCI_MODE);
,Oxdqx u7 if (r < 0)
QR4v6*VpD goto out;
-.^Mt.) }
R#1m_6I file->f_pos = info->read_offset;
mXhr: e break;
H[-zQ#I9 ^4s#nf:} case TCGETS:
ReSP)%oW dev_dbg(&client->dev, "%s: TCGETS\n", __func__);
]t(g7lc}U j{p0yuZ)< r = -ENOIOCTLCMD;
Em4TEv break;
:+E>UzT [c>X Q default:
[W^6=7EO dev_err(&client->dev, "Unknown ioctl 0x%x\n", cmd);
.':SD{ r = -ENOIOCTLCMD;
rzqCQZHL5 break;
<6(u%t0k5 }
:dLS+cTC :FxZdE out:
B"+Ygvxb mutex_unlock(&info->mutex);
dr9I+c7u UKX'A)$ return r;
u;=("S{"0 }
-$e\m]
}Z zlSwKd( static int pn544_open(struct inode *inode, struct file *file)
.'X$SF` {
g{<3*, struct pn544_info *info = container_of(file->private_data,
|W#^L`!G struct pn544_info, miscdev);
^]aDLjD struct i2c_client *client = info->i2c_dev;
W:9L!+m^ int r = 0;
dX+DE(y (5Cm+Sy dev_dbg(&client->dev, "%s: info: %p, client %p\n", __func__,
Yt|{l info, info->i2c_dev);
ia?8Z"&lK _Z8zD[l mutex_lock(&info->mutex);
"h:xdaIE/p m4 4aKqw) /*
VK$+Nm) * Only 1 at a time.
>
]6Eb`v * XXX: maybe user (counter) would work better
z&-3H/ */
7&T1RB'> if (info->state != PN544_ST_COLD) {
Xq J@NgsY r = -EBUSY;
^-=,q.[7 goto out;
p&ZD1qa }
2Db[dk( ] "J[Cr m file->f_pos = info->read_offset;
`D?vmSQ r = pn544_enable(info, HCI_MODE);
|@d7o]eM| CZbp}:| out:
?]sj!7 mutex_unlock(&info->mutex);
8c~b7F
\ return r;
lT$A;7[ }
1}V_:~7 2abWIw4 static int pn544_close(struct inode *inode, struct file *file)
y;Dw%m {
>TtkG|/U-T struct pn544_info *info = container_of(file->private_data,
_jnH!Mw struct pn544_info, miscdev);
\W*ouH struct i2c_client *client = info->i2c_dev;
Jh }3AoD L
TO1LAac dev_dbg(&client->dev, "%s: info: %p, client %p\n",
t@!oc"z}@ __func__, info, info->i2c_dev);
L4Kkbt<x E5 Y92vu mutex_lock(&info->mutex);
AZtZa'hbkQ pn544_disable(info);
!@*Ac$J>$ mutex_unlock(&info->mutex);
\UN7lDH vH7"tz&RIp return 0;
gv<9XYByt }
0!!pNK%( rF
7EO%, static const struct file_operations pn544_fops = {
(5'qEi ea .owner = THIS_MODULE,
)e{~x
u .llseek = no_llseek,
cty.)e= .read = pn544_read,
5z#>>|1># .write = pn544_write,
L6U[H#3( .poll = pn544_poll,
RCgs3JIE+2 .open = pn544_open,
"1`c^ .release = pn544_close,
>dZ x+7 .unlocked_ioctl = pn544_ioctl,
HtS:'~DYo };
!y?g$e` ly6?jVJ #ifdef CONFIG_PM
SAXjB;VH6 static int pn544_suspend(struct device *dev)
aoMQ_@0 {
P1H`NOC struct i2c_client *client = to_i2c_client(dev);
L suc*Ps struct pn544_info *info;
%VSST?aUvX int r = 0;
UGr7,+N&w /koNcpJ dev_info(&client->dev, "***\n%s: client %p\n***\n", __func__, client);
o_os; R}Z"Yxx info = i2c_get_clientdata(client);
aI+:rk^ dev_info(&client->dev, "%s: info: %p, client %p\n", __func__,
8|V6Rg A% info, client);
>^>
\y8on _<kE32Bb mutex_lock(&info->mutex);
$5cLhi"` Q_LPLmM switch (info->state) {
Q|+m)A4@ case PN544_ST_FW_READY:
* F~"4g /* Do not suspend while upgrading FW, please! */
3vmLftZE} r = -EPERM;
%E~4 Ur break;
u[PO'6Kzd PS(9?rX#+ case PN544_ST_READY:
rb&^ ei9B /*
GEIMCg(TRj * CHECK: Device should be in standby-mode. No way to check?
'-gk))u>) * Allowing low power mode for the regulator is potentially
L=4?vs * dangerous if pn544 does not go to suspension.
"uqa~R{ */
B>#zrCD break;
0>VgO{X M)Tv(7 case PN544_ST_COLD:
bo\|mvB~ break;
"op1x to };
FhAuTZk X#1So .}c mutex_unlock(&info->mutex);
241YJ return r;
\*!g0C8 o }
^?&Jq_oU wL5IAkq static int pn544_resume(struct device *dev)
Q3wD6!'&m {
bN<c5 struct i2c_client *client = to_i2c_client(dev);
u)R>ozER struct pn544_info *info = i2c_get_clientdata(client);
@\u)k int r = 0;
I)_072^O vlp]!7v dev_dbg(&client->dev, "%s: info: %p, client %p\n", __func__,
.eK1xwhJ info, client);
#x)G2T'? 3=T<c?[ mutex_lock(&info->mutex);
$axaI$bE [UR+G8X21m switch (info->state) {
5#$E4k:YV case PN544_ST_READY:
~9h6"0K! /*
m\"M`o
B * CHECK: If regulator low power mode is allowed in
3f
eI * pn544_suspend, we should go back to normal mode
[)Xu60?Q * here.
8[(c'rl|)| */
g^}X3NUn break;
Xb#x^?| {nm#aA%, case PN544_ST_COLD:
6\OSIxJZF break;
A{y3yH`#h XOJ/$y case PN544_ST_FW_READY:
ItC*[ break;
qECc[)B };
cS4e}\q, 1g2%f9G mutex_unlock(&info->mutex);
k[A=:H1" K34ca-~ return r;
_Dwn@{[(8 }
Z9~~vf# JjyQ static SIMPLE_DEV_PM_OPS(pn544_pm_ops, pn544_suspend, pn544_resume);
\EUc17 #endif
\eI )(,A K
,f 1c} static struct device_attribute pn544_attr =
HP*x?|4 __ATTR(nfc_test, S_IRUGO, pn544_test, NULL);
0*B_$E06 [-s0'z static int __devinit pn544_probe(struct i2c_client *client,
8kH'ai const struct i2c_device_id *id)
?u'JhZ {
u;h9Ra1 struct pn544_info *info;
@>(l}5U5 struct pn544_nfc_platform_data *pdata;
W-7yi`5 int r = 0;
x%vt$dy*8 q fadsVp dev_dbg(&client->dev, "%s\n", __func__);
^p|@{4f] dev_dbg(&client->dev, "IRQ: %d\n", client->irq);
h"#^0$f .7+_ubj&, /* private data allocation */
pFGdm3pV info = kzalloc(sizeof(struct pn544_info), GFP_KERNEL);
XH1so1h if (!info) {
PKwHq<vAsB dev_err(&client->dev,
frc>0\ "Cannot allocate memory for pn544_info.\n");
&nZ=w#_ r = -ENOMEM;
Il~ph9{JH goto err_info_alloc;
i\}, }
+]`MdOu 6H.D`"cj info->buflen = max(PN544_MSG_MAX_SIZE, PN544_MAX_I2C_TRANSFER);
A~h.,<+" info->buf = kzalloc(info->buflen, GFP_KERNEL);
.IYOtS if (!info->buf) {
n#,AZ& dev_err(&client->dev,
:*A6Ba "Cannot allocate memory for pn544_info->buf.\n");
nDui9C r = -ENOMEM;
*2=:(OK goto err_buf_alloc;
L7q%u.nB1 }
x8b w# KB*[b info->regs[0].supply = reg_vdd_io;
G80d!*7 info->regs[1].supply = reg_vbat;
)q&uvfQ1( info->regs[2].supply = reg_vsim;
'u_'y r = regulator_bulk_get(&client->dev, ARRAY_SIZE(info->regs),
WASs'Gx info->regs);
eu^z&R!um if (r < 0)
Q4CxtY goto err_kmalloc;
WH/r$.& @"'1"$ info->i2c_dev = client;
?G0=\U<
o, info->state = PN544_ST_COLD;
ylmf^G@JC info->read_irq = PN544_NONE;
E"pq ZP = mutex_init(&info->read_mutex);
oxH S7b mutex_init(&info->mutex);
:HMnU37m W init_waitqueue_head(&info->read_wait);
=WFMqBh<` i2c_set_clientdata(client, info);
&0Wv+2l@ pdata = client->dev.platform_data;
WP2|0ib if (!pdata) {
3MNo&0M9 dev_err(&client->dev, "No platform data\n");
.OX.z~":y r = -EINVAL;
42ttmN1F goto err_reg;
%I&Hx<Hj }
Tj<W4+p{ k3}ymhUf if (!pdata->request_resources) {
cDm_QYQ dev_err(&client->dev, "request_resources() missing\n");
I$9t^82j r = -EINVAL;
)z2Tm4>iql goto err_reg;
h1FM)n[E7 }
<M7@JgC & FUvZMA$ r = pdata->request_resources(client);
z"=#<C if (r) {
?9OiF-:n dev_err(&client->dev, "Cannot get platform resources\n");
0rsdDME[ goto err_reg;
qZ6P(5X }
o*'J8El\y^ [0Z
r z+q r = request_threaded_irq(client->irq, NULL, pn544_irq_thread_fn,
.!l#z|/x IRQF_TRIGGER_RISING, PN544_DRIVER_NAME,
2Z\6xb|u info);
2}b1PMpZG if (r < 0) {
.v/s9'lB dev_err(&client->dev, "Unable to register IRQ handler\n");
~Pv4X2MO goto err_res;
b H?dyS6Bx }
&r/a\t,8n UfOF's_'< /* If we don't have the test we don't need the sysfs file */
H.'MQ if (pdata->test) {
4WzB=C(f r = device_create_file(&client->dev, &pn544_attr);
0p*(<8D} if (r) {
7t0\}e dev_err(&client->dev,
HZkC3$ "sysfs registration failed, error %d\n", r);
hg]\~#&- goto err_irq;
l{\~I }
d Am(uJ }
`.#e4 FBW PfF7*}P info->miscdev.minor = MISC_DYNAMIC_MINOR;
CsQ}eW8uEf info->miscdev.name = PN544_DRIVER_NAME;
]uWx<aDB info->miscdev.fops = &pn544_fops;
,*bI0mFZ info->miscdev.parent = &client->dev;
bJx{mq
r = misc_register(&info->miscdev);
M})2y+ if (r < 0) {
&t5pJ`$(Cy dev_err(&client->dev, "Device registration failed\n");
600-e;p goto err_sysfs;
4u"V52 }
c03A_2% =zK7`5 dev_dbg(&client->dev, "%s: info: %p, pdata %p, client %p\n",
D ( <_1 __func__, info, pdata, client);
u/hFf3 T,TKt% return 0;
zq8z#FN =L#tSa=M" err_sysfs:
1WfN_JKB5 if (pdata->test)
kC!7<%( device_remove_file(&client->dev, &pn544_attr);
/=FQ{tLr err_irq:
"6gu6f free_irq(client->irq, info);
H8`K?SXU err_res:
V+nqQ~pJ& if (pdata->free_resources)
R1!{,*Gy pdata->free_resources();
{I@@i8)] err_reg:
*QG>U [ regulator_bulk_free(ARRAY_SIZE(info->regs), info->regs);
;E,%\< err_kmalloc:
DCACj-f kfree(info->buf);
i
jg'X#E err_buf_alloc:
8;5 UO,`T kfree(info);
w5bD err_info_alloc:
Aq^1(-g return r;
MV-fDqA( }
>dUnk)7 r\F`xtR( static __devexit int pn544_remove(struct i2c_client *client)
N*|Mfpf {
9} :n struct pn544_info *info = i2c_get_clientdata(client);
;4z6="<Y struct pn544_nfc_platform_data *pdata = client->dev.platform_data;
zRx-xWo G)?VC^Q dev_dbg(&client->dev, "%s\n", __func__);
CKNC"Y*X Co4QWyt: misc_deregister(&info->miscdev);
$*Njvr7 if (pdata->test)
<*i
' device_remove_file(&client->dev, &pn544_attr);
u `1cXL[' 5sao+dZ"| if (info->state != PN544_ST_COLD) {
aW$sd) if (pdata->disable)
</>;PnzE pdata->disable();
Xjt/ G):L %4Y/-xF}9, info->read_irq = PN544_NONE;
q=M!YWz }
9*h?g+\ z:u e]7(. free_irq(client->irq, info);
21O!CvX if (pdata->free_resources)
O3bo3Cm$ pdata->free_resources();
.RxH-]xk yEJ}!/ regulator_bulk_free(ARRAY_SIZE(info->regs), info->regs);
|bk.gh kfree(info->buf);
2ro4{^(_ kfree(info);
uLD%M av qt=gz6! return 0;
ryy".'v }
-fI-d1@ R*`A',]:9 static struct i2c_driver pn544_driver = {
6Z] * ce<r .driver = {
;?"]S/16, .name = PN544_DRIVER_NAME,
;f:}gMK #ifdef CONFIG_PM
#eD@sEn .pm = &pn544_pm_ops,
?B.>VnYZ/a #endif
+Em+W#i%? },
)mT{w9u .probe = pn544_probe,
})#6BN .id_table = pn544_id_table,
v)mO"\ .remove = __devexit_p(pn544_remove),
81u}J9z; };
Nih8(pbe ~L)9XK^15 static int __init pn544_init(void)
PE4#dx^ {
"q5Tw+KCfu int r;
k\8]fh)J\7 Tp2 `eY5 pr_debug(DRIVER_DESC ": %s\n", __func__);
' te4mY} oswS<t{Z r = i2c_add_driver(&pn544_driver);
AC;ja$A# if (r) {
}ac0} pr_err(PN544_DRIVER_NAME ": driver registration failed\n");
*^e06xc: return r;
0l=g$G
\% }
Q>]FO _yw]Cacr\ return 0;
,_?P[~1 }
uH7$/ :_E=&4&g static void __exit pn544_exit(void)
0\*[7!`s {
,)^4H>~V i2c_del_driver(&pn544_driver);
K;Qlg{v pr_info(DRIVER_DESC ", Exiting.\n");
lArYlR} }
~jWG U-m LxaR1E(Cc' module_init(pn544_init);
7~n<%q/6 module_exit(pn544_exit);
Loo48 ^t,sehpR:l MODULE_LICENSE("GPL");
<2@V$$Qg.~ MODULE_DESCRIPTION(DRIVER_DESC);
e=S51q_0