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

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

上一主题 下一主题
离线mark83136
 

性别:
帅哥
发帖
1210
金币
360
提示:会员销售的附件,下载积分 = 版块积分 + 销售积分       只看楼主 倒序阅读 使用道具 0楼 发表于: 2015-07-09
yPQ{tS*t  
/* \pzvoj7{  
* Driver for the PN544 NFC chip. \ 3LD^[qi  
* >8 JvnBFx=  
* Copyright (C) Nokia Corporation epG;=\f}m`  
* aSF&^/j  
* Author: Jari Vanhala <ext-jari.vanhala@nokia.com> =~0XdS/1  
* Contact: Matti Aaltonen <matti.j.aaltonen@nokia.com> I^ >zr.z A  
* |Q I3H]T7  
* This program is free software; you can redistribute it and/or hPk+vvXtK  
* modify it under the terms of the GNU General Public License I9Sh~vTm=u  
* version 2 as published by the Free Software Foundation. {VNeh  
* RsOK5XnQn  
* This program is distributed in the hope that it will be useful, wlpbfO e/  
* but WITHOUT ANY WARRANTY; without even the implied warranty of C,<TAm  
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.    See the >{??/fBd-  
* GNU General Public License for more details. < Ihn1?  
* o>*{5>#k'  
* You should have received a copy of the GNU General Public License 'P Yl%2  
* along with this program; if not, write to the Free Software _ x'StD  
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA )xK!i.  
*/ z::2O/ho  
4dok/ +Ec  
#include <linux/completion.h> .XE]vo  
#include <linux/crc-ccitt.h> @'rO=(-b  
#include <linux/delay.h> '9[_ w$~(  
#include <linux/interrupt.h> (\I =v".  
#include <linux/kernel.h> y@Or2bO#  
#include <linux/miscdevice.h> 5 O6MI4:  
#include <linux/module.h> LtU+w*Gj  
#include <linux/mutex.h> lxz %b C@  
#include <linux/nfc/pn544.h> [T^6Kzz  
#include <linux/poll.h> lz*2wGI9  
#include <linux/regulator/consumer.h> A+l"  
#include <linux/serial_core.h> /* for TCGETS */ o{hKt?  
#include <linux/slab.h> 37[C^R!1c  
a;zcAeX  
#define DRIVER_CARD    "PN544 NFC" V& nN/CF  
#define DRIVER_DESC    "NFC driver for PN544" > @%!r  
;'Q{ ywr  
static struct i2c_device_id pn544_id_table[] = { GkC88l9z  
    { PN544_DRIVER_NAME, 0 }, <>:kAT,sP  
    { } @gj5'  
}; cs5Xd  
MODULE_DEVICE_TABLE(i2c, pn544_id_table); hf-S6PEsM  
/PCQv_Y&,/  
#define HCI_MODE    0 [y:LA ~q  
#define FW_MODE        1 {h=Ai[|l4Q  
p[eRK .$!  
enum pn544_state { "osYw\unI  
    PN544_ST_COLD, =3:ltI.'*I  
    PN544_ST_FW_READY, H:_`]X"  
    PN544_ST_READY, 8B+uNN~%]  
}; EGt)tI&  
72 6y/o  
enum pn544_irq { ;4bu=<%  
    PN544_NONE, #?*jdN:  
    PN544_INT, ;:4puv+]  
}; >xjy P!bca  
6uyf  
struct pn544_info { U&XoT-p$L  
    struct miscdevice miscdev; KOQTvJ_#  
    struct i2c_client *i2c_dev; S@#L!sT`u  
    struct regulator_bulk_data regs[3]; |(<L!6  
e'Pa@]VaC  
    enum pn544_state state; i&$uG[&P  
    wait_queue_head_t read_wait; 7,zARWB!?  
    loff_t read_offset; 5ZVTI,4K  
    enum pn544_irq read_irq; kYAvzuGRb  
    struct mutex read_mutex; /* Serialize read_irq access */ rBf?kDt6l  
    struct mutex mutex; /* Serialize info struct access */  #L)rz u  
    u8 *buf; Z7^}G=*  
    size_t buflen; 1#(1Bs6X  
}; ?zEF?LJoK  
SXEiyy[7v  
static const char reg_vdd_io[]    = "Vdd_IO"; EHZSM5hu  
static const char reg_vbat[]    = "VBat"; %8Z,t+'  
static const char reg_vsim[]    = "VSim"; /HRaX!|E#  
qAS^5|(b[  
/* sysfs interface */ 1N+#(<x@,  
static ssize_t pn544_test(struct device *dev, m C Ge*V}  
              struct device_attribute *attr, char *buf) Nz;;X\GI  
{ YYHm0pc  
    struct pn544_info *info = dev_get_drvdata(dev); Jy_'(hG  
    struct i2c_client *client = info->i2c_dev; hbeC|_+   
    struct pn544_nfc_platform_data *pdata = client->dev.platform_data; * 5n:+Tw(  
^U}0D^jDeE  
    return snprintf(buf, PAGE_SIZE, "%d\n", pdata->test()); pQNFH)=nw  
} U\ued=H  
zTLn*?  
static int pn544_enable(struct pn544_info *info, int mode) +$t%L  
{ F0Hbklr  
    struct pn544_nfc_platform_data *pdata; ~|rkt`8p  
    struct i2c_client *client = info->i2c_dev; 7;NV 1RV  
j,XKu5w)Oi  
    int r; %jk PrI  
e`r;`a&  
    r = regulator_bulk_enable(ARRAY_SIZE(info->regs), info->regs); ,X^_w g  
    if (r < 0) TpgBS4q  
        return r; 37xxVbik  
=f!M=D  
    pdata = client->dev.platform_data; p/h&_^EXU  
    info->read_irq = PN544_NONE; i7V~LO:gq  
    if (pdata->enable) 0K ?(xB  
        pdata->enable(mode); B! V{.p  
cqx1NWlY  
    if (mode) { 1 1CJT  
        info->state = PN544_ST_FW_READY; $8k_M   
        dev_dbg(&client->dev, "now in FW-mode\n"); T;@>O^  
    } else { Wi^rnr'S s  
        info->state = PN544_ST_READY; s~ A8/YoU}  
        dev_dbg(&client->dev, "now in HCI-mode\n"); }eM<A$J  
    } N_D+d4@  
p'~5[JR:  
    usleep_range(10000, 15000); =joXP$n^  
K"7;Y#1g  
    return 0; G4' U;  
} t [hocl/6  
CDnz &?  
static void pn544_disable(struct pn544_info *info) 1 ],, Ar5  
{ tr8Cx~<  
    struct pn544_nfc_platform_data *pdata; ~aAJn IO  
    struct i2c_client *client = info->i2c_dev; CqK#O'\  
|SKG4_wGe  
    pdata = client->dev.platform_data; AijTT%  
    if (pdata->disable) Aq%^>YAp  
        pdata->disable(); bpa O`[*  
xc.D!Iav  
    info->state = PN544_ST_COLD; ROS"VV<  
-WvgK"k  
    dev_dbg(&client->dev, "Now in OFF-mode\n"); Y>Hl0$:=  
f\|?_k]  
    msleep(PN544_RESETVEN_TIME); FK# E7 K  
m\M+pjz  
    info->read_irq = PN544_NONE; F LI8r:  
    regulator_bulk_disable(ARRAY_SIZE(info->regs), info->regs); PMhhPw]  
} KTjlWxD  
D"4&9"CU  
static int check_crc(u8 *buf, int buflen) 2 BX GVo  
{ bDBO+qA  
    u8 len; W#I:j: p  
    u16 crc; -MU.Hu  
6F.7Ws <  
    len = buf[0] + 1; X|E+K  
    if (len < 4 || len != buflen || len > PN544_MSG_MAX_SIZE) { cO+Xzd;838  
        pr_err(PN544_DRIVER_NAME U q w}4C/0  
               ": CRC; corrupt packet len %u (%d)\n", len, buflen); dyiEK)$h  
        print_hex_dump(KERN_DEBUG, "crc: ", DUMP_PREFIX_NONE, s%[GQQ-N  
                   16, 2, buf, buflen, false); exO#>th1  
        return -EPERM; r>~d[,^$m4  
    } jS3(>  
    crc = crc_ccitt(0xffff, buf, len - 2); s^YTI\L \  
    crc = ~crc; _T|H69 J  
4bev* [k  
    if (buf[len-2] != (crc & 0xff) || buf[len-1] != (crc >> 8)) { E? eWv)//  
        pr_err(PN544_DRIVER_NAME ": CRC error 0x%x != 0x%x 0x%x\n", C]yQ "b  
               crc, buf[len-1], buf[len-2]); 76A>^Bs\/  
:q64K?X  
        print_hex_dump(KERN_DEBUG, "crc: ", DUMP_PREFIX_NONE, 7k=F6k0)  
                   16, 2, buf, buflen, false); Ldhk^/+  
        return -EPERM; 2FIR]@MQd  
    } E<Dh_K  
    return 0; 'nWs0iH.  
} 'K`Rbhy  
51G=RYay9  
static int pn544_i2c_write(struct i2c_client *client, u8 *buf, int len) fA_%8CjI  
{ gZlw  
    int r; N^ s!!Sbpq  
0vuKGjK  
    if (len < 4 || len != (buf[0] + 1)) { g:DTVq  
        dev_err(&client->dev, "%s: Illegal message length: %d\n", ,{{#a*nd  
            __func__, len); mvq7G  
        return -EINVAL; 7e c0Xh1  
    } AwXt @!(  
6L,lq;  
    if (check_crc(buf, len)) 9Ue7 ~"=  
        return -EINVAL; a We Bav}_  
S6T!qH{6  
    usleep_range(3000, 6000); qfG tUkSSb  
2Za ,4'  
    r = i2c_master_send(client, buf, len); ^0~c 7`k`V  
    dev_dbg(&client->dev, "send: %d\n", r); >bA$SN  
B3 dA%\'  
    if (r == -EREMOTEIO) { /* Retry, chip was in standby */ o)#q9Vk%b  
        usleep_range(6000, 10000); & &" 'dL  
        r = i2c_master_send(client, buf, len); q11QAx4p  
        dev_dbg(&client->dev, "send2: %d\n", r); Q^lQi\[  
    } cK[R1 ReH  
Wm)-zvNY;  
    if (r != len) m0|Ae@g~3  
        return -EREMOTEIO; ,2,SG/BB  
*M wfod  
    return r; )WVItqQKV  
} \5Vp6^  
BbrT f"`  
static int pn544_i2c_read(struct i2c_client *client, u8 *buf, int buflen) fW.GNX8  
{ 2y+70(E1  
    int r; +ze}0lrEL  
    u8 len; =a)iVXSB]  
(_w %  
    /* {_zV5 V  
     * You could read a packet in one go, but then you'd need to read =[P%_v``  
     * max size and rest would be 0xff fill, so we do split reads. Kc%n(,+%"  
     */ /M^V 2=  
    r = i2c_master_recv(client, &len, 1); ,!6M* |  
    dev_dbg(&client->dev, "recv1: %d\n", r); _%wK}eH+sy  
.!JMPf"QEI  
    if (r != 1) #\pP2  
        return -EREMOTEIO; d7"U WY^  
xH<'GB)  
    if (len < PN544_LLC_HCI_OVERHEAD) wJ+U[a  
        len = PN544_LLC_HCI_OVERHEAD; vpm ]9>1[  
    else if (len > (PN544_MSG_MAX_SIZE - 1)) dD/t_ {h  
        len = PN544_MSG_MAX_SIZE - 1; uxa=KM1H  
g7xbyB o7  
    if (1 + len > buflen) /* len+(data+crc16) */ +_qh)HX  
        return -EMSGSIZE; A\".t=+7  
(R_CUH  
    buf[0] = len; 3ppuQ Q  
:E>&s9Yj?  
    r = i2c_master_recv(client, buf + 1, len); ~ HK1X  
    dev_dbg(&client->dev, "recv2: %d\n", r); of8mwnZR  
I*D<J$ 9N  
    if (r != len) XzT78  
        return -EREMOTEIO; /M3y)K`^  
umQi  
    usleep_range(3000, 6000); > P<z |8  
[ULwzjss#L  
    return r + 1; &/s~? Iq  
} pC*BA<?Rg  
9i0M/vx  
static int pn544_fw_write(struct i2c_client *client, u8 *buf, int len) 9>N\sOh  
{ [ njx7d  
    int r; br0u@G  
=G( *gx  
    dev_dbg(&client->dev, "%s\n", __func__); 4|nQ=bIau  
}0QN[$H!  
    if (len < PN544_FW_HEADER_SIZE || _yj1:TtCNT  
        (PN544_FW_HEADER_SIZE + (buf[1] << 8) + buf[2]) != len) FZiZg;  
        return -EINVAL; ^:qD.h>&  
 bH*@,EE  
    r = i2c_master_send(client, buf, len); X Vw-G }5  
    dev_dbg(&client->dev, "fw send: %d\n", r); 5U%MoH  
I>{!U$  
    if (r == -EREMOTEIO) { /* Retry, chip was in standby */ Sv7 i! j  
        usleep_range(6000, 10000); "YJ[$TG  
        r = i2c_master_send(client, buf, len); s=MT,  
        dev_dbg(&client->dev, "fw send2: %d\n", r); vQUZVq5M  
    } %N )e91wC  
t)9]<pN%  
    if (r != len) cTM$ZNin  
        return -EREMOTEIO; =HVfJ"vK  
2B-.}OJ  
    return r; *B1x`=  
} V1<ow'^i  
ejVdxVr\7  
static int pn544_fw_read(struct i2c_client *client, u8 *buf, int buflen) {>@QJlE0  
{ %y>+1hakkX  
    int r, len; @g4Shlx|  
:c y >c2  
    if (buflen < PN544_FW_HEADER_SIZE) |xh&p(  
        return -EINVAL; :G-1YA  
D9.`hs0  
    r = i2c_master_recv(client, buf, PN544_FW_HEADER_SIZE); f')c/Yw  
    dev_dbg(&client->dev, "FW recv1: %d\n", r); Q"%QQo}}  
`mzb(b E  
    if (r < 0) 4qt+uNe!  
        return r; 9RQU?  
U/Wrh($ #4  
    if (r < PN544_FW_HEADER_SIZE) eIg+PuQD]  
        return -EINVAL; D*\v0=P'?  
bDDqaO ,8  
    len = (buf[1] << 8) + buf[2]; Q"%S~&#'  
    if (len == 0) /* just header, no additional data */ jv =EheD  
        return r; y;nvR6)  
Yt+h2ft!  
    if (len > buflen - PN544_FW_HEADER_SIZE) +3;Ody"59  
        return -EMSGSIZE; EUy(T1Cl&&  
|jT2W  
    r = i2c_master_recv(client, buf + PN544_FW_HEADER_SIZE, len); _1  p DA  
    dev_dbg(&client->dev, "fw recv2: %d\n", r); l&L,7BX  
w9f _b3  
    if (r != len) O2.' -  
        return -EINVAL; 3pSj kS|?>  
]]TqP{H  
    return r + PN544_FW_HEADER_SIZE; *YtB )6j  
} ;L~p|sF  
URA0ey`  
static irqreturn_t pn544_irq_thread_fn(int irq, void *dev_id) U]hF   
{ zBY~lNB  
    struct pn544_info *info = dev_id; 6YmP[%  
    struct i2c_client *client = info->i2c_dev; )JhT1j Qc  
4(=kE>n}  
    BUG_ON(!info); 5qbq,#Pf  
    BUG_ON(irq != info->i2c_dev->irq); ;~+]! U  
*0y{ ~@  
    dev_dbg(&client->dev, "IRQ\n"); Kb&V!#o)  
<sX VW  
    mutex_lock(&info->read_mutex); j13DJ.xu  
    info->read_irq = PN544_INT; !`&\Lx_  
    mutex_unlock(&info->read_mutex); \\:|Odd  
+-BwQ{92[:  
    wake_up_interruptible(&info->read_wait); R,t$"bOd  
=gjDCx$|  
    return IRQ_HANDLED; :et#0!  
} $wV1*$1NM  
nPFwPk8=M  
static enum pn544_irq pn544_irq_state(struct pn544_info *info) PD6_)PXn  
{ 7 [d ?  
    enum pn544_irq irq; *fnvZw?  
rrqQCn9  
    mutex_lock(&info->read_mutex); ;3"@g]e  
    irq = info->read_irq; sw;|'N$:<  
    mutex_unlock(&info->read_mutex); WOX}Sw"  
    /* m#e*c [*G  
     * XXX: should we check GPIO-line status directly? < Ek/8x  
     * return pdata->irq_status() ? PN544_INT : PN544_NONE; W:`#% :C  
     */ tfYB_N  
; s|w{.<:  
    return irq; PFrfd_s{>\  
} 'yY>as  
""% A'TZ  
static ssize_t pn544_read(struct file *file, char __user *buf, 8'#/LA[uPe  
              size_t count, loff_t *offset) C <B<o[:H  
{ T2FE+A]n9  
    struct pn544_info *info = container_of(file->private_data, $t}<85YCQ  
                           struct pn544_info, miscdev); pOT7;-#n  
    struct i2c_client *client = info->i2c_dev; hyg8wI  
    enum pn544_irq irq; =*Z5!W'd  
    size_t len; 2`?!+")  
    int r = 0; y_p.Gzy(^}  
-e*ZCwQ  
    dev_dbg(&client->dev, "%s: info: %p, count: %zu\n", __func__, Hfym30  
        info, count); z>m=h)9d~  
4x;_AN  
    mutex_lock(&info->mutex); |[$~\MU  
SaOYu &>  
    if (info->state == PN544_ST_COLD) {  :A1:  
        r = -ENODEV; ?D`T7KSe~D  
        goto out; U_B(( Z(g  
    } rl08 R  
2]cRXJ7h  
    irq = pn544_irq_state(info); _S}A=hK'  
    if (irq == PN544_NONE) { 4_/?:$KO  
        if (file->f_flags & O_NONBLOCK) { /Ncm^b4  
            r = -EAGAIN; c;2#,m^  
            goto out; P{Lf5V9# <  
        } Ztr Cv?  
tDg}Ys=4K>  
        if (wait_event_interruptible(info->read_wait, u #w29Pm  
                         (info->read_irq == PN544_INT))) { d5`3wd]]'v  
            r = -ERESTARTSYS; V)(R]BK{  
            goto out; ^T::-pN*  
        } <h-vjz  
    } #_93f |  
**3 z;58i  
    if (info->state == PN544_ST_FW_READY) { QX4ai3v  
        len = min(count, info->buflen); 6( CDNMzj  
1KM`i  
        mutex_lock(&info->read_mutex); Uu 8,@W+  
        r = pn544_fw_read(info->i2c_dev, info->buf, len); `-h8vj5uG  
        info->read_irq = PN544_NONE; hrGM|_BE  
        mutex_unlock(&info->read_mutex); phnV7D(E  
. mLK`c6  
        if (r < 0) { #X 52/8G  
            dev_err(&info->i2c_dev->dev, "FW read failed: %d\n", r); a`[uNgDO  
            goto out; %w7u]-tR  
        } ?']5dD  
{!t7[Ctb  
        print_hex_dump(KERN_DEBUG, "FW read: ", DUMP_PREFIX_NONE, x^4xq#Bb7  
                   16, 2, info->buf, r, false); 9RN-suE[  
Od4E x;F  
        *offset += r; ?T9(Vw  
        if (copy_to_user(buf, info->buf, r)) { VXIP0p@  
            r = -EFAULT; CHrFM@CM  
            goto out; ?=m?jNa;nC  
        } m< _S_c  
    } else { ojyIQk+  
        len = min(count, info->buflen); {M-YHX>*;g  
?qCK7 $ j  
        mutex_lock(&info->read_mutex); ;r_F[E2z  
        r = pn544_i2c_read(info->i2c_dev, info->buf, len); .ZvM^GJb  
        info->read_irq = PN544_NONE; S4=~`$eP  
        mutex_unlock(&info->read_mutex); -gSUjP  
C{gyj}5  
        if (r < 0) { I!e})Y  
            dev_err(&info->i2c_dev->dev, "read failed (%d)\n", r); 91 =OF*w  
            goto out; N(I&  
        } ^6_e=jIN  
        print_hex_dump(KERN_DEBUG, "read: ", DUMP_PREFIX_NONE, QFYWA1<pDh  
                   16, 2, info->buf, r, false); }:X*7 n(&  
 J5^'HU3  
        *offset += r; Ut2y;2)a  
        if (copy_to_user(buf, info->buf, r)) { q#<^^4U  
            r = -EFAULT; o.0ci+z@  
            goto out; .C8PitS  
        } )+:EJH~  
    } tjupJ*Rt  
uc;8 K,[t  
out: UK<Nj<-'t  
    mutex_unlock(&info->mutex); "jG}B.l=,  
bbrXgQ`s+w  
    return r; -$\+' \  
} NR`C(^}  
 o4|M0  
static unsigned int pn544_poll(struct file *file, poll_table *wait) G1vNt7  
{ {phNds%  
    struct pn544_info *info = container_of(file->private_data, 28 ?\  
                           struct pn544_info, miscdev); bD/~eIcWL  
    struct i2c_client *client = info->i2c_dev; dBz/7&Q   
    int r = 0; O8h%3&  
xai*CY@cQ  
    dev_dbg(&client->dev, "%s: info: %p\n", __func__, info); a(l29>  
 Vh_P/C+  
    mutex_lock(&info->mutex); z6*X%6,8  
r"P|dlV-  
    if (info->state == PN544_ST_COLD) { Wk)OkIFR  
        r = -ENODEV; ,yiX# ;j  
        goto out; $<}$DH_Y  
    } \WxukYH  
vEJWFoeEFm  
    poll_wait(file, &info->read_wait, wait); ZrsBm_Rx  
a{L d  
    if (pn544_irq_state(info) == PN544_INT) { I}1NB3>^  
        r = POLLIN | POLLRDNORM; #qK:J;Sn3  
        goto out; G3Z)Z) N  
    } k?+?v?I =  
out: <g"{Wv: h  
    mutex_unlock(&info->mutex); e)d`pQ6  
sS*3=Yh  
    return r; #d6)#:uss  
} P GqQ@6B  
aDU<wxnSvO  
static ssize_t pn544_write(struct file *file, const char __user *buf, =vX/{C  
               size_t count, loff_t *ppos) ~"nxE  
{ 4y|BOVl  
    struct pn544_info *info = container_of(file->private_data, A1O' |7X  
                           struct pn544_info, miscdev); YtmrRDQs  
    struct i2c_client *client = info->i2c_dev; 3}}38A|4  
    ssize_t    len; t'n pG}`tE  
    int r; nLXlU*ES  
LRL,m_gt  
    dev_dbg(&client->dev, "%s: info: %p, count %zu\n", __func__, hgPa6Kd  
        info, count); ;ub;l h3  
HiZ*+T.B  
    mutex_lock(&info->mutex); h`^jyoF"(  
b,7k)ND1F  
    if (info->state == PN544_ST_COLD) { b3=rG(0f  
        r = -ENODEV; F3On?x)  
        goto out; l9{hq/V  
    } -|$@-fY;  
v[1aW v:  
    /* "~sW"n(F_  
     * XXX: should we detect rset-writes and clean possible KcWN,!G  
     * read_irq state Va"0>KX  
     */ d; boIP`M;  
    if (info->state == PN544_ST_FW_READY) { TM%| '^)  
        size_t fw_len; "\: `/k3  
=$'6(aDH  
        if (count < PN544_FW_HEADER_SIZE) { >mwlsL~X  
            r = -EINVAL; 0"<H;7K#W  
            goto out; &."iFe  
        } P3x8UR=fS  
_kef 0K6  
        len = min(count, info->buflen); oH97=>  
        if (copy_from_user(info->buf, buf, len)) { 3l rT3a3vV  
            r = -EFAULT; Ag-(5:  
            goto out; $*^7iT4q_t  
        } f\|w '  
o_izl \  
        print_hex_dump(KERN_DEBUG, "FW write: ", DUMP_PREFIX_NONE, 03$mYS_?  
                   16, 2, info->buf, len, false); )1?y 8_B  
?+))}J5N\  
        fw_len = PN544_FW_HEADER_SIZE + (info->buf[1] << 8) + ZF!h<h&,  
            info->buf[2]; 0"jY.*_EW  
^9v4OUG  
        if (len > fw_len) /* 1 msg at a time */ $0W|26;  
            len = fw_len; u|\1h LXX  
g|o,uD  
        r = pn544_fw_write(info->i2c_dev, info->buf, len); yb<fpM  
    } else { Vr3Zu{&2  
        if (count < PN544_LLC_MIN_SIZE) { p*XANGA  
            r = -EINVAL; (p"%O  
            goto out; \"7*{L:  
        } =Qy<GeY  
j`{?OYD  
        len = min(count, info->buflen); Hus)c3Ty7  
        if (copy_from_user(info->buf, buf, len)) { T^zXt?  
            r = -EFAULT; =*oJEy"  
            goto out; /:cd\A}  
        } A#e%^{q$  
wW Lj?;bx  
        print_hex_dump(KERN_DEBUG, "write: ", DUMP_PREFIX_NONE, hZm"t/aKc  
                   16, 2, info->buf, len, false); yl'u'-Zb6  
5?f ^Rz  
        if (len > (info->buf[0] + 1)) /* 1 msg at a time */ M[NV )q/)  
            len  = info->buf[0] + 1; )*u8/U  
1.}d.t  
        r = pn544_i2c_write(info->i2c_dev, info->buf, len); { a =#B)6  
    } mVj9, q0  
out: KYB`D.O   
    mutex_unlock(&info->mutex); '+@=ILj>  
wo3d#=   
    return r; D(~U6SR  
4S7v:1~xe  
} p/ ,=OaVU  
x`mG<Yt  
static long pn544_ioctl(struct file *file, unsigned int cmd, unsigned long arg) '6DBs8>1  
{ 6,pnw  
    struct pn544_info *info = container_of(file->private_data, FUiRTRIYe  
                           struct pn544_info, miscdev); 0 j^Kgx  
    struct i2c_client *client = info->i2c_dev; 4j-Xi  
    struct pn544_nfc_platform_data *pdata; ?al'F  q  
    unsigned int val; ko!)s  
    int r = 0; 1a/++4O.|  
QFA8N  
    dev_dbg(&client->dev, "%s: info: %p, cmd: 0x%x\n", __func__, info, cmd); :a!^   
t$`r4Lb9/  
    mutex_lock(&info->mutex); >>,e4s,  
|44Ploz2b  
    if (info->state == PN544_ST_COLD) { %:i7s-0w  
        r = -ENODEV; 91/Q9xY  
        goto out; )7hqJa-V  
    } )j6~Wy@4  
sWhZby7  
    pdata = info->i2c_dev->dev.platform_data; [:dY0r+  
    switch (cmd) { 9p]QM)M  
    case PN544_GET_FW_MODE: 59LG{R2  
        dev_dbg(&client->dev, "%s:  PN544_GET_FW_MODE\n", __func__); [DuttFX^x  
-oGdk|Yn  
        val = (info->state == PN544_ST_FW_READY); vz&|J   
        if (copy_to_user((void __user *)arg, &val, sizeof(val))) { 5%"V[lDx@  
            r = -EFAULT; @@f"%2ZR[  
            goto out; ,CJWO bn3  
        } =F|{# F  
/WcG{Wdp  
        break; 6bg ;q(*7  
hW<%R]^|  
    case PN544_SET_FW_MODE: PrqlTT}Px  
        dev_dbg(&client->dev, "%s:  PN544_SET_FW_MODE\n", __func__); Lj({[H7D!  
q])K,)  
        if (copy_from_user(&val, (void __user *)arg, sizeof(val))) { Xg6Jh``  
            r = -EFAULT; 1er TldX  
            goto out; 1C+13LE$U  
        } {p2!|A&a  
hE{K=Tz$  
        if (val) { `bq<$e  
            if (info->state == PN544_ST_FW_READY) J0WxR&%a)  
                break; )$2QZ qX  
-_g0C^:<,  
            pn544_disable(info); \doUTr R  
            r = pn544_enable(info, FW_MODE); '@v\{ l  
            if (r < 0) b/K PaNv  
                goto out; 'ms-*c&  
        } else { vO^m;['  
            if (info->state == PN544_ST_READY) .^`{1%  
                break; T=DbBy0-  
            pn544_disable(info); yZY\MB/  
            r = pn544_enable(info, HCI_MODE); :U|1xgB  
            if (r < 0) P\tB~SZ*  
                goto out; bIDj[-CDG  
        } Q-okt RK  
        file->f_pos = info->read_offset; ),%%$G\  
        break; fUWG*o9  
FjHv   
    case TCGETS: P8:dU(nlW  
        dev_dbg(&client->dev, "%s:  TCGETS\n", __func__); ~7w"nIs<c  
RMV/&85?y  
        r = -ENOIOCTLCMD; r8?gD&c}  
        break; -m zIT4  
N{!i=A  
    default: ,Fl)^Gl8?  
        dev_err(&client->dev, "Unknown ioctl 0x%x\n", cmd); ?>:g?.+  
        r = -ENOIOCTLCMD; 0],r0  
        break;  4\N ;2N  
    } bSlF=jT[S  
+.PxzL3?  
out: rBzuKQK}J  
    mutex_unlock(&info->mutex); k9R4Y\8P  
?=msH=N<l  
    return r; >h9I M$2  
} Tk[ $5u*,  
4"(Bu/24  
static int pn544_open(struct inode *inode, struct file *file) x j)F55e?  
{ VT)oLj/A  
    struct pn544_info *info = container_of(file->private_data, _ A y9p[l  
                           struct pn544_info, miscdev); Wis~$"  
    struct i2c_client *client = info->i2c_dev; net@j#}j-  
    int r = 0; B"w?;EeV.  
wU36sCo  
    dev_dbg(&client->dev, "%s: info: %p, client %p\n", __func__, <$$yw=ef  
        info, info->i2c_dev); H2 {+)  
?p{Nwl#  
    mutex_lock(&info->mutex); s\(k<Ks  
+)om^e@.  
    /* 2,oKVm+  
     * Only 1 at a time. :S83vE81WK  
     * XXX: maybe user (counter) would work better J4C.+![!Ah  
     */ \:'/'^=#|  
    if (info->state != PN544_ST_COLD) { r +i($ jMs  
        r = -EBUSY; 2wg5#i  
        goto out; HWrO"b*tO  
    } f}ji?p  
M)+H{5bt  
    file->f_pos = info->read_offset; XEp{VC@=  
    r = pn544_enable(info, HCI_MODE); !Pvf;rNI1T  
0S_~\t  
out: %XDc,AR[  
    mutex_unlock(&info->mutex); 8W(*~}ydYY  
    return r; ~H_/zK6e  
} 2WL|wwA  
/9*B)m"  
static int pn544_close(struct inode *inode, struct file *file) %N6A+5H  
{ x /S}Q8!"}  
    struct pn544_info *info = container_of(file->private_data, 7kLz[N6Ll  
                           struct pn544_info, miscdev); kx{{_w  
    struct i2c_client *client = info->i2c_dev; %@aSe2B  
N^G Mp,8  
    dev_dbg(&client->dev, "%s: info: %p, client %p\n", ,eW%{[g(  
        __func__, info, info->i2c_dev); #U4F0BdA  
a2O75 kWnm  
    mutex_lock(&info->mutex); jXx<`I+]  
    pn544_disable(info); NO>w+-dGS  
    mutex_unlock(&info->mutex); 85$m[+md  
{X+3;&@  
    return 0; L.2^`mZs  
} .t-4o<7 3  
Oc#syfO  
static const struct file_operations pn544_fops = { Tbih+# ?  
    .owner        = THIS_MODULE, $y&E(J  
    .llseek        = no_llseek, PI)+Jr%L  
    .read        = pn544_read, #e1>H1eU  
    .write        = pn544_write, 81F/G5  
    .poll        = pn544_poll, X1|njJGO1  
    .open        = pn544_open, qp }Cqi  
    .release    = pn544_close, %QGC8Tz  
    .unlocked_ioctl    = pn544_ioctl, ,j{,h_Op  
}; ||= )d&  
py!|\00}  
#ifdef CONFIG_PM &< `NT D  
static int pn544_suspend(struct device *dev) F?*-4I-  
{ ^WgX Qtn  
    struct i2c_client *client = to_i2c_client(dev); [< ?s?Ci  
    struct pn544_info *info; bKY7/w<dP  
    int r = 0; X,_2FJv  
 .-c4wm}  
    dev_info(&client->dev, "***\n%s: client %p\n***\n", __func__, client); x%m%_2%Z  
H3 ^},.  
    info = i2c_get_clientdata(client);  a=9:[  
    dev_info(&client->dev, "%s: info: %p, client %p\n", __func__, ay ;S4c/_  
         info, client); gMmaK0uhS  
? 7n`A >T  
    mutex_lock(&info->mutex); 61>.vT8P  
5h-SCB>P  
    switch (info->state) { mbxZL<ua  
    case PN544_ST_FW_READY: C.yQ=\U2  
        /* Do not suspend while upgrading FW, please! */ zuad~%D<I  
        r = -EPERM; NZLxHD]mp  
        break; f!uwzHA`?  
3g,`.I_  
    case PN544_ST_READY: u(>^3PJ+  
        /* ]"hFC<w  
         * CHECK: Device should be in standby-mode. No way to check? Oi'5ytsES  
         * Allowing low power mode for the regulator is potentially y<|7z99L  
         * dangerous if pn544 does not go to suspension. mb TEp*H  
         */ ]I dk:et  
        break; ]Ji.Zk  
X ::JV7hu  
    case PN544_ST_COLD: @s;;O\  
        break; EzM ?Nft  
    }; w !-gJmX>  
{j?FNOJn  
    mutex_unlock(&info->mutex); xw,IJ/E$1  
    return r; KE5kOU;  
} WUe{vV#S'0  
+US!YU  
static int pn544_resume(struct device *dev) 6 l|DU7i  
{ @]%IK(|  
    struct i2c_client *client = to_i2c_client(dev); .\ULbN3Z  
    struct pn544_info *info = i2c_get_clientdata(client); d9f C<Tp  
    int r = 0; I(L,8n5  
{ M4gF8(M  
    dev_dbg(&client->dev, "%s: info: %p, client %p\n", __func__, _~l5u8{^6  
        info, client); f;o5=)Y  
{l1.2!  
    mutex_lock(&info->mutex); .Ni\\  
TCwFPlF|  
    switch (info->state) { GX!G>  
    case PN544_ST_READY: a od-3"7[  
        /* ~*&H$6NJS  
         * CHECK: If regulator low power mode is allowed in -8ywO"6  
         * pn544_suspend, we should go back to normal mode u^ +7hkk  
         * here. 58tARLDr  
         */ Ha0M)0Anv  
        break; S}m)OmrmA  
taHJ ub  
    case PN544_ST_COLD: %op**@4/t\  
        break; Q0`wt.}V2  
;40/yl3r3[  
    case PN544_ST_FW_READY: D[[|")Fn  
        break; H7&8\ FNa  
    }; 0y'H~(  
:1. L}4"gg  
    mutex_unlock(&info->mutex); Y1W1=Uc uk  
,*TmIPNK  
    return r; p SH=%u>  
} +aCv&sg  
TTX5EDCrC  
static SIMPLE_DEV_PM_OPS(pn544_pm_ops, pn544_suspend, pn544_resume); W fN2bsx>  
#endif j ?3wvw6T  
7 UKh688  
static struct device_attribute pn544_attr = mUAi4N  
    __ATTR(nfc_test, S_IRUGO, pn544_test, NULL); 7?!d^$B  
9]([\%)  
static int __devinit pn544_probe(struct i2c_client *client,  c(f  
                 const struct i2c_device_id *id) bivuqKA  
{ 4<w.8rR:A  
    struct pn544_info *info; { =9,n\85#  
    struct pn544_nfc_platform_data *pdata; ,GhS[VJjR  
    int r = 0; UawyDs  
9IdA%RM~mH  
    dev_dbg(&client->dev, "%s\n", __func__); CAig ]=2'  
    dev_dbg(&client->dev, "IRQ: %d\n", client->irq); Fc)@,/R"v  
HTv2#  
    /* private data allocation */ })H wh).  
    info = kzalloc(sizeof(struct pn544_info), GFP_KERNEL); h ohfE3rd  
    if (!info) { Zgp4`)}:  
        dev_err(&client->dev, hn7# L  
            "Cannot allocate memory for pn544_info.\n"); g-4M3of  
        r = -ENOMEM; S:#lH?<_  
        goto err_info_alloc; e9Wa<i 8  
    } e }?db  
gS!:+G%  
    info->buflen = max(PN544_MSG_MAX_SIZE, PN544_MAX_I2C_TRANSFER); z3{G9Np  
    info->buf = kzalloc(info->buflen, GFP_KERNEL); q"CVcLi9  
    if (!info->buf) { q5J5>  
        dev_err(&client->dev, s0TORl6Z|  
            "Cannot allocate memory for pn544_info->buf.\n"); L:$ ,v^2  
        r = -ENOMEM; D# 9m\o_  
        goto err_buf_alloc; ]!W=^!  
    } &)# ihK_  
'6nA F  
    info->regs[0].supply = reg_vdd_io; IEL%!RFG  
    info->regs[1].supply = reg_vbat; <6%?OJhp  
    info->regs[2].supply = reg_vsim; nY[WRt w  
    r = regulator_bulk_get(&client->dev, ARRAY_SIZE(info->regs), XFVE>/H  
                 info->regs); \S `:y?[Y  
    if (r < 0) x xHY+(m  
        goto err_kmalloc; Z\bmW%av  
w8")w*9Lmg  
    info->i2c_dev = client; v ,i%Q$  
    info->state = PN544_ST_COLD; t4."/ .=+  
    info->read_irq = PN544_NONE; ih-#5M@  
    mutex_init(&info->read_mutex); m+`cS=-.  
    mutex_init(&info->mutex); NR$3%0 nC6  
    init_waitqueue_head(&info->read_wait); *nT<m\C6  
    i2c_set_clientdata(client, info); { T/[cu<  
    pdata = client->dev.platform_data; OR P\b  
    if (!pdata) { 9!ngy*\x  
        dev_err(&client->dev, "No platform data\n"); |"q5sym8Y_  
        r = -EINVAL; /* (Kr'c  
        goto err_reg; *P[ hy  
    } M><yGaaX/  
Ye%~I`@?  
    if (!pdata->request_resources) { '0;l]/i.  
        dev_err(&client->dev, "request_resources() missing\n"); Y1 w9y  
        r = -EINVAL; rET\n(AJ  
        goto err_reg; }`@vF|2L  
    } L8@f-Kk  
^x]r`b  
    r = pdata->request_resources(client);  C#.->\  
    if (r) { ~p6 V,Q  
        dev_err(&client->dev, "Cannot get platform resources\n"); 1;bh^WMJ  
        goto err_reg; ;DQ ZT  
    } g\|PcoLm  
N@4w! HpJ  
    r = request_threaded_irq(client->irq, NULL, pn544_irq_thread_fn, x`eo"5.$  
                 IRQF_TRIGGER_RISING, PN544_DRIVER_NAME, +q<jAW A  
                 info); Y sC>i`n9  
    if (r < 0) { /aCc17>2V{  
        dev_err(&client->dev, "Unable to register IRQ handler\n"); df8k7D;~e  
        goto err_res; .fqN|[>  
    } 93>jr<A  
;$,U~0  
    /* If we don't have the test we don't need the sysfs file */ G{~J|{t\yz  
    if (pdata->test) { |w~nVRb  
        r = device_create_file(&client->dev, &pn544_attr); /obfw^  
        if (r) { wq`s-qZu  
            dev_err(&client->dev, fivw~z|[@  
                "sysfs registration failed, error %d\n", r); ;J( 8 L  
            goto err_irq; sPpH*,(  
        } *uRBzO}  
    } ]"As1"  
[-1^-bb  
    info->miscdev.minor = MISC_DYNAMIC_MINOR; dmtr*pM_  
    info->miscdev.name = PN544_DRIVER_NAME; (*9$`!wS  
    info->miscdev.fops = &pn544_fops; x M/+L:_<  
    info->miscdev.parent = &client->dev; T3.&R#1M8-  
    r = misc_register(&info->miscdev); S&5&];Ag  
    if (r < 0) { HQ_Ok `  
        dev_err(&client->dev, "Device registration failed\n"); aH(J,XY  
        goto err_sysfs; wYXQlxdy  
    } un"Gozmt5  
a#(?P.6  
    dev_dbg(&client->dev, "%s: info: %p, pdata %p, client %p\n", BN5[,J  
        __func__, info, pdata, client); w>&aEv/f  
mkk6`,ov  
    return 0;  #4NaL  
Pl06:g2I  
err_sysfs: PcMD])Z{G  
    if (pdata->test) ha<[b ue  
        device_remove_file(&client->dev, &pn544_attr); z]y.W`i   
err_irq: =!A_^;NQf  
    free_irq(client->irq, info); j?\Qh  
err_res: ./Zk`-OBT  
    if (pdata->free_resources) F`W?II?  
        pdata->free_resources(); Y=?3 js?O  
err_reg: cxC6n%!;y  
    regulator_bulk_free(ARRAY_SIZE(info->regs), info->regs); k/_ 59@)  
err_kmalloc: 2%Ri,4SRb  
    kfree(info->buf); :gibfk]C  
err_buf_alloc: 9!\B6=r y4  
    kfree(info); <?.&^|kS  
err_info_alloc: [#vH'y  
    return r; VQt0  4?  
} X=&ET)8-Y  
z (wc0I  
static __devexit int pn544_remove(struct i2c_client *client) OU_gdp  
{ !sP {gi#=  
    struct pn544_info *info = i2c_get_clientdata(client); &-6Gc;f8  
    struct pn544_nfc_platform_data *pdata = client->dev.platform_data; ;?i W%:_,  
oxA<VWUNT  
    dev_dbg(&client->dev, "%s\n", __func__); '3fu  
qS$Ox?Bw#u  
    misc_deregister(&info->miscdev); dt]-,Y  
    if (pdata->test) L|7R9+ZG  
        device_remove_file(&client->dev, &pn544_attr); prF%.(G2)  
b94DJzL1z  
    if (info->state != PN544_ST_COLD) { $szqy?i 0?  
        if (pdata->disable) 3z?> j]  
            pdata->disable(); Do7Tj  
L|xbR#v  
        info->read_irq = PN544_NONE; g-bK|6?yz  
    } I3I/bofz  
;bib/  
    free_irq(client->irq, info); wKxtre(v  
    if (pdata->free_resources) <{cQM$ #  
        pdata->free_resources(); \V8PhO;j  
*Kg ks4  
    regulator_bulk_free(ARRAY_SIZE(info->regs), info->regs); Ya"a`ozq  
    kfree(info->buf); b5vC'B-!  
    kfree(info); Qn.om=KDs@  
sIGMA$EK  
    return 0; 4F'LBS]=0  
} WPMSm<[  
oW*16>IN9l  
static struct i2c_driver pn544_driver = { 9}<ile7^  
    .driver = { +gtbcF@rx  
        .name = PN544_DRIVER_NAME, 'Aq{UGN  
#ifdef CONFIG_PM pJ"qu,w  
        .pm = &pn544_pm_ops, d#4**BM  
#endif J @1!Oq>  
    }, .}TZxla0Zr  
    .probe = pn544_probe, <uw9DU7G  
    .id_table = pn544_id_table, m8hk:4Ae  
    .remove = __devexit_p(pn544_remove), *fS"ym@  
}; K`zdc`/  
)yZ^[uJ}3C  
static int __init pn544_init(void) ;))+>%SGCt  
{ l4YJ c  
    int r; !ons]^km  
agDM~=#F  
    pr_debug(DRIVER_DESC ": %s\n", __func__); @9RM9zK.q  
6}Ci>_i4#  
    r = i2c_add_driver(&pn544_driver); ,Uqs1#r  
    if (r) { 9 -a0:bP  
        pr_err(PN544_DRIVER_NAME ": driver registration failed\n"); oQVgyj.  
        return r; WO>nIo5Y  
    } ,m|h<faZL  
j-}O0~Jz  
    return 0; 08\, <9  
} )g%d:xI  
G}raA%  
static void __exit pn544_exit(void)  |TH\`U  
{ y/7\?qfTk  
    i2c_del_driver(&pn544_driver); 4p;`C  
    pr_info(DRIVER_DESC ", Exiting.\n"); :J&oX <nF^  
} Jk n>S#SZ  
Y)2,PES=  
module_init(pn544_init); Moza".fiN  
module_exit(pn544_exit); 7.j?U  
6 V=9M:  
MODULE_LICENSE("GPL"); D'Df JwA  
MODULE_DESCRIPTION(DRIVER_DESC); mNTzUoZF'@  


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

精彩

感动

搞笑

开心

愤怒

一般

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