论坛风格切换切换到宽版
发帖 回复
返回列表  提醒:不能用迅雷等P2P下载,否则下载失败标(二级)的板块,需二级才能下载,没二级不要购买,下载不了
  • 2601阅读
  • 0回复

RK3288  nfc技持的NFC 驱动 pn544 [复制链接]

上一主题 下一主题
离线mark83136
 

性别:
帅哥
发帖
1210
金币
360
提示:会员销售的附件,下载积分 = 版块积分 + 销售积分       只看楼主 倒序阅读 使用道具 0楼 发表于: 2015-07-09
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.O a$  
* 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_  
*/ <O x[![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 */ 8 WP>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 N gNGq\!  
T.q2tC[bR  
enum pn544_state { ?}||?2=P  
    PN544_ST_COLD, Re%[t9 F&  
    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 2 N  
=;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#w4 Pp  
    u8 *buf; c '|*{%<e2  
    size_t buflen; _h%Jf{nu  
}; .X g.,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.  
zzG=!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)i c7 b  
1@Ba7>%'  
    info->state = PN544_ST_COLD; dcKpsX  
c((3B  
    dev_dbg(&client->dev, "Now in OFF-mode\n"); %+r(*Q+0$f  
NbWEP\dS'z  
    msleep(PN544_RESETVEN_TIME); $`xpn#l z  
~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[|yt W  
               ": 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  
`LH9@Z{  
        print_hex_dump(KERN_DEBUG, "crc: ", DUMP_PREFIX_NONE, ^uX"04>;  
                   16, 2, buf, buflen, false); K*^'t ltJ  
        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; q q^[(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,+Us B%  
     * max size and rest would be 0xff fill, so we do split reads. $YBH;^#  
     */ Xp^>SSt:4  
    r = i2c_master_recv(client, &len, 1); )sEAP Ika  
    dev_dbg(&client->dev, "recv1: %d\n", r); -r_Pp}s  
ZDr TPnA[  
    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; H Lt;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%)  
mv xg|<  
    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 */ p2 y 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:W N  
    info->read_irq = PN544_INT; vC J  
    mutex_unlock(&info->read_mutex); X'[S Cs  
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^goi 1  
              size_t count, loff_t *offset)  [Fr.ik  
{ M_UhFY='  
    struct pn544_info *info = container_of(file->private_data, +&-/$\"  
                           struct pn544_info, miscdev); S1;#5 8  
    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>f9bb  
    } 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); 2 Do^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); ="P 3TP  
T8JM4F  
        *offset += r; KFkKr>S :  
        if (copy_to_user(buf, info->buf, r)) { 5<<e_n.2q  
            r = -EFAULT; \vs,$h  
            goto out; U z>5!_  
        } fF;Oz"I{\  
    } else { -z-58FLlO  
        len = min(count, info->buflen); LL7a 20  
~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|m A  
            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^  
' jR83A*  
    poll_wait(file, &info->read_wait, wait); 6C9KT;6  
J xi>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) { ZZ A!Y9ia2  
        r = -ENODEV; \ v44Vmfz  
        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); OOQf a#~k  
        if (copy_from_user(info->buf, buf, len)) { @ \J RxJ  
            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(W E+  
*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__); Bf1GHn Xv  
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: Mu Z\<;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\g P@  
            r = pn544_enable(info, FW_MODE); jq.@<<j|$  
            if (r < 0) ]d$)G4X 1  
                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); ,Oxdqxu7  
            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>Uz T  
[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?8 Z"&lK  
_Z8zD[l  
    mutex_lock(&info->mutex); "h:xdaIE/p  
m4 4aK qw)  
    /* 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) { XqJ@NgsY  
        r = -EBUSY; ^-=,q.[7  
        goto out;  p&ZD1qa  
    } 2Db[dk( ]  
"J[Crm  
    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); Lsuc*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"Y xx  
    info = i2c_get_clientdata(client); aI+:rk^  
    dev_info(&client->dev, "%s: info: %p, client %p\n", __func__, 8|V6RgA%  
         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~4Ur  
        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; "op1xto  
    }; FhAuTZk  
X#1So.}c  
    mutex_unlock(&info->mutex); 241YJ  
    return r; \*!g0C 8 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  
X OJ/$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#  
J j yQ  
static SIMPLE_DEV_PM_OPS(pn544_pm_ops, pn544_suspend, pn544_resume); \EUc17  
#endif \eI )(,A  
K ,f1c}  
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); e u^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); oxHS7b  
    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<H j  
    } Tj<W4+p{  
k3}ymhUf  
    if (!pdata->request_resources) { cDm_QYQ  
        dev_err(&client->dev, "request_resources() missing\n"); I$9 t^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  
        } dAm( uJ  
    } `.#e4 FBW  
PfF7*}P  
    info->miscdev.minor = MISC_DYNAMIC_MINOR; CsQ}eW8uEf  
    info->miscdev.name = PN544_DRIVER_NAME; ]uWx<aD B  
    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/h Ff3  
T,TKt%  
    return 0; zq8 z#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); w5b D  
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  
C o4QWyt:  
    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:ue]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@s En  
        .pm = &pn544_pm_ops, ?B.>VnYZ/a  
#endif +Em+W#i%?  
    }, )mT{w9u  
    .probe = pn544_probe, })#6 BN  
    .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  


评价一下你浏览此帖子的感受

精彩

感动

搞笑

开心

愤怒

一般

差劲
快速回复
限150 字节
 
上一个 下一个