xref: /aosp_15_r20/external/libese/libese-hw/nxp/pn80t/nq_nci.c (revision 5c4dab75aa57366379dce576b1a9e082a44e2b3a)
1*5c4dab75SAndroid Build Coastguard Worker /*
2*5c4dab75SAndroid Build Coastguard Worker  * Copyright (C) 2017 The Android Open Source Project
3*5c4dab75SAndroid Build Coastguard Worker  *
4*5c4dab75SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*5c4dab75SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*5c4dab75SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*5c4dab75SAndroid Build Coastguard Worker  *
8*5c4dab75SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*5c4dab75SAndroid Build Coastguard Worker  *
10*5c4dab75SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*5c4dab75SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*5c4dab75SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*5c4dab75SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*5c4dab75SAndroid Build Coastguard Worker  * limitations under the License.
15*5c4dab75SAndroid Build Coastguard Worker  *
16*5c4dab75SAndroid Build Coastguard Worker  * Platform implementation for a nq-nci extension driver.
17*5c4dab75SAndroid Build Coastguard Worker  *
18*5c4dab75SAndroid Build Coastguard Worker  * The driver presents the following interface on a miscdev:
19*5c4dab75SAndroid Build Coastguard Worker  * - ioctl():
20*5c4dab75SAndroid Build Coastguard Worker  *   - for setting and getting power.
21*5c4dab75SAndroid Build Coastguard Worker  *     This handles SVDD_PWR_REQ and NFC_VEN muxing.
22*5c4dab75SAndroid Build Coastguard Worker  *     (ESE_RST is not connected in this case.)
23*5c4dab75SAndroid Build Coastguard Worker  * - read():
24*5c4dab75SAndroid Build Coastguard Worker  *   - For reading arbitrary amounts of data.
25*5c4dab75SAndroid Build Coastguard Worker  *     CS is asserted and deasserted on each call, but the clock
26*5c4dab75SAndroid Build Coastguard Worker  *     also appears to do the same which keeps the ese data available
27*5c4dab75SAndroid Build Coastguard Worker  *     as far as I can tell.
28*5c4dab75SAndroid Build Coastguard Worker  * - write():
29*5c4dab75SAndroid Build Coastguard Worker  *   - For writing arbitrary amounts of data.
30*5c4dab75SAndroid Build Coastguard Worker  *     CS is asserted as with read() calls, so the less fragmented
31*5c4dab75SAndroid Build Coastguard Worker  *     the better.
32*5c4dab75SAndroid Build Coastguard Worker  *
33*5c4dab75SAndroid Build Coastguard Worker  * All GPIO toggling and chip select requirements are handled behind this
34*5c4dab75SAndroid Build Coastguard Worker  * interface.
35*5c4dab75SAndroid Build Coastguard Worker  *
36*5c4dab75SAndroid Build Coastguard Worker  */
37*5c4dab75SAndroid Build Coastguard Worker 
38*5c4dab75SAndroid Build Coastguard Worker #include <errno.h>
39*5c4dab75SAndroid Build Coastguard Worker #include <fcntl.h>
40*5c4dab75SAndroid Build Coastguard Worker #include <limits.h>
41*5c4dab75SAndroid Build Coastguard Worker #include <stdint.h>
42*5c4dab75SAndroid Build Coastguard Worker #include <stdlib.h>
43*5c4dab75SAndroid Build Coastguard Worker #include <string.h>
44*5c4dab75SAndroid Build Coastguard Worker #include <sys/ioctl.h>
45*5c4dab75SAndroid Build Coastguard Worker #include <unistd.h>
46*5c4dab75SAndroid Build Coastguard Worker 
47*5c4dab75SAndroid Build Coastguard Worker #include "../include/ese/hw/nxp/pn80t/common.h"
48*5c4dab75SAndroid Build Coastguard Worker 
49*5c4dab75SAndroid Build Coastguard Worker #ifndef UNUSED
50*5c4dab75SAndroid Build Coastguard Worker #define UNUSED(x) x __attribute__((unused))
51*5c4dab75SAndroid Build Coastguard Worker #endif
52*5c4dab75SAndroid Build Coastguard Worker 
53*5c4dab75SAndroid Build Coastguard Worker /* From kernel/drivers/nfc/nq-nci.h */
54*5c4dab75SAndroid Build Coastguard Worker #define ESE_SET_PWR _IOW(0xE9, 0x02, unsigned int)
55*5c4dab75SAndroid Build Coastguard Worker #define ESE_GET_PWR _IOR(0xE9, 0x03, unsigned int)
56*5c4dab75SAndroid Build Coastguard Worker #define ESE_CLEAR_GPIO _IOW(0xE9, 0x11, unsigned int)
57*5c4dab75SAndroid Build Coastguard Worker 
58*5c4dab75SAndroid Build Coastguard Worker static const char kDevicePath[] = "/dev/pn81a";
59*5c4dab75SAndroid Build Coastguard Worker 
60*5c4dab75SAndroid Build Coastguard Worker struct PlatformHandle {
61*5c4dab75SAndroid Build Coastguard Worker   int fd;
62*5c4dab75SAndroid Build Coastguard Worker };
63*5c4dab75SAndroid Build Coastguard Worker 
platform_toggle_bootloader(void * blob,int val)64*5c4dab75SAndroid Build Coastguard Worker int platform_toggle_bootloader(void *blob, int val) {
65*5c4dab75SAndroid Build Coastguard Worker   const struct PlatformHandle *handle = blob;
66*5c4dab75SAndroid Build Coastguard Worker   if (!handle) {
67*5c4dab75SAndroid Build Coastguard Worker     return -1;
68*5c4dab75SAndroid Build Coastguard Worker   }
69*5c4dab75SAndroid Build Coastguard Worker   return ioctl(handle->fd, ESE_CLEAR_GPIO, val);
70*5c4dab75SAndroid Build Coastguard Worker }
71*5c4dab75SAndroid Build Coastguard Worker 
platform_toggle_reset(void * blob,int val)72*5c4dab75SAndroid Build Coastguard Worker int platform_toggle_reset(void *blob, int val) {
73*5c4dab75SAndroid Build Coastguard Worker   const struct PlatformHandle *handle = blob;
74*5c4dab75SAndroid Build Coastguard Worker   if (!handle) {
75*5c4dab75SAndroid Build Coastguard Worker     return -1;
76*5c4dab75SAndroid Build Coastguard Worker   }
77*5c4dab75SAndroid Build Coastguard Worker   /* 0=power and 1=no power in the kernel. */
78*5c4dab75SAndroid Build Coastguard Worker   return ioctl(handle->fd, ESE_SET_PWR, !val);
79*5c4dab75SAndroid Build Coastguard Worker }
80*5c4dab75SAndroid Build Coastguard Worker 
platform_init(void * hwopts)81*5c4dab75SAndroid Build Coastguard Worker void *platform_init(void *hwopts) {
82*5c4dab75SAndroid Build Coastguard Worker   /* TODO(wad): It may make sense to pass in the dev path here. */
83*5c4dab75SAndroid Build Coastguard Worker   if (hwopts != NULL) {
84*5c4dab75SAndroid Build Coastguard Worker     return NULL;
85*5c4dab75SAndroid Build Coastguard Worker   }
86*5c4dab75SAndroid Build Coastguard Worker 
87*5c4dab75SAndroid Build Coastguard Worker   struct PlatformHandle *handle = calloc(1, sizeof(*handle));
88*5c4dab75SAndroid Build Coastguard Worker   if (!handle) {
89*5c4dab75SAndroid Build Coastguard Worker     ALOGE("%s: unable to allocate memory for handle", __func__);
90*5c4dab75SAndroid Build Coastguard Worker     return NULL;
91*5c4dab75SAndroid Build Coastguard Worker   }
92*5c4dab75SAndroid Build Coastguard Worker   handle->fd = open(kDevicePath, O_RDWR);
93*5c4dab75SAndroid Build Coastguard Worker   if (handle->fd < 0) {
94*5c4dab75SAndroid Build Coastguard Worker     ALOGE("%s: opening '%s' failed: %s", __func__, kDevicePath,
95*5c4dab75SAndroid Build Coastguard Worker           strerror(errno));
96*5c4dab75SAndroid Build Coastguard Worker     free(handle);
97*5c4dab75SAndroid Build Coastguard Worker     return NULL;
98*5c4dab75SAndroid Build Coastguard Worker   }
99*5c4dab75SAndroid Build Coastguard Worker   return handle;
100*5c4dab75SAndroid Build Coastguard Worker }
101*5c4dab75SAndroid Build Coastguard Worker 
platform_release(void * blob)102*5c4dab75SAndroid Build Coastguard Worker int platform_release(void *blob) {
103*5c4dab75SAndroid Build Coastguard Worker   struct PlatformHandle *handle = blob;
104*5c4dab75SAndroid Build Coastguard Worker   if (!handle) {
105*5c4dab75SAndroid Build Coastguard Worker     return -1;
106*5c4dab75SAndroid Build Coastguard Worker   }
107*5c4dab75SAndroid Build Coastguard Worker   /* Power off and cooldown should've happened via common code. */
108*5c4dab75SAndroid Build Coastguard Worker   close(handle->fd);
109*5c4dab75SAndroid Build Coastguard Worker   free(handle);
110*5c4dab75SAndroid Build Coastguard Worker   return 0;
111*5c4dab75SAndroid Build Coastguard Worker }
112*5c4dab75SAndroid Build Coastguard Worker 
platform_wait(void * UNUSED (blob),long usec)113*5c4dab75SAndroid Build Coastguard Worker int platform_wait(void *UNUSED(blob), long usec) {
114*5c4dab75SAndroid Build Coastguard Worker   return usleep((useconds_t)usec);
115*5c4dab75SAndroid Build Coastguard Worker }
116*5c4dab75SAndroid Build Coastguard Worker 
nq_transmit(struct EseInterface * ese,const uint8_t * buf,uint32_t len,int UNUSED (complete))117*5c4dab75SAndroid Build Coastguard Worker uint32_t nq_transmit(struct EseInterface *ese, const uint8_t *buf, uint32_t len,
118*5c4dab75SAndroid Build Coastguard Worker                      int UNUSED(complete)) {
119*5c4dab75SAndroid Build Coastguard Worker   struct NxpState *ns = NXP_PN80T_STATE(ese);
120*5c4dab75SAndroid Build Coastguard Worker   const struct Pn80tPlatform *platform = ese->ops->opts;
121*5c4dab75SAndroid Build Coastguard Worker   uint32_t bytes = 0;
122*5c4dab75SAndroid Build Coastguard Worker   ALOGV("nq_nci:%s: called [%d]", __func__, len);
123*5c4dab75SAndroid Build Coastguard Worker   if (len > INT_MAX) {
124*5c4dab75SAndroid Build Coastguard Worker     ese_set_error(ese, kNxpPn80tErrorTransmitSize);
125*5c4dab75SAndroid Build Coastguard Worker     ALOGE("Unexpectedly large transfer attempted: %u", len);
126*5c4dab75SAndroid Build Coastguard Worker     return 0;
127*5c4dab75SAndroid Build Coastguard Worker   }
128*5c4dab75SAndroid Build Coastguard Worker   if (len == 0)
129*5c4dab75SAndroid Build Coastguard Worker     return len;
130*5c4dab75SAndroid Build Coastguard Worker   const struct PlatformHandle *handle = ns->handle;
131*5c4dab75SAndroid Build Coastguard Worker   while (bytes < len) {
132*5c4dab75SAndroid Build Coastguard Worker     ssize_t ret = write(handle->fd, (void *)(buf + bytes), len - bytes);
133*5c4dab75SAndroid Build Coastguard Worker     if (ret < 0) {
134*5c4dab75SAndroid Build Coastguard Worker       if (errno == EAGAIN || errno == EINTR) {
135*5c4dab75SAndroid Build Coastguard Worker         continue;
136*5c4dab75SAndroid Build Coastguard Worker       }
137*5c4dab75SAndroid Build Coastguard Worker       ese_set_error(ese, kNxpPn80tErrorTransmit);
138*5c4dab75SAndroid Build Coastguard Worker       ALOGE("%s: failed to write to hw (ret=%zd, errno=%d)", __func__, ret,
139*5c4dab75SAndroid Build Coastguard Worker             errno);
140*5c4dab75SAndroid Build Coastguard Worker       return 0;
141*5c4dab75SAndroid Build Coastguard Worker     }
142*5c4dab75SAndroid Build Coastguard Worker     bytes += ret;
143*5c4dab75SAndroid Build Coastguard Worker   }
144*5c4dab75SAndroid Build Coastguard Worker   return len;
145*5c4dab75SAndroid Build Coastguard Worker }
146*5c4dab75SAndroid Build Coastguard Worker 
nq_receive(struct EseInterface * ese,uint8_t * buf,uint32_t len,int UNUSED (complete))147*5c4dab75SAndroid Build Coastguard Worker uint32_t nq_receive(struct EseInterface *ese, uint8_t *buf, uint32_t len,
148*5c4dab75SAndroid Build Coastguard Worker                     int UNUSED(complete)) {
149*5c4dab75SAndroid Build Coastguard Worker   const struct Pn80tPlatform *platform = ese->ops->opts;
150*5c4dab75SAndroid Build Coastguard Worker   struct NxpState *ns = NXP_PN80T_STATE(ese);
151*5c4dab75SAndroid Build Coastguard Worker   ALOGV("nq_nci:%s: called [%d]", __func__, len);
152*5c4dab75SAndroid Build Coastguard Worker   if (!ns) {
153*5c4dab75SAndroid Build Coastguard Worker     ALOGE("NxpState was NULL");
154*5c4dab75SAndroid Build Coastguard Worker     return 0;
155*5c4dab75SAndroid Build Coastguard Worker   }
156*5c4dab75SAndroid Build Coastguard Worker   if (len > INT_MAX) {
157*5c4dab75SAndroid Build Coastguard Worker     ese_set_error(ese, kNxpPn80tErrorReceiveSize);
158*5c4dab75SAndroid Build Coastguard Worker     ALOGE("Unexpectedly large receive attempted: %u", len);
159*5c4dab75SAndroid Build Coastguard Worker     return 0;
160*5c4dab75SAndroid Build Coastguard Worker   }
161*5c4dab75SAndroid Build Coastguard Worker   const struct PlatformHandle *handle = ns->handle;
162*5c4dab75SAndroid Build Coastguard Worker   if (len == 0) {
163*5c4dab75SAndroid Build Coastguard Worker     return 0;
164*5c4dab75SAndroid Build Coastguard Worker   }
165*5c4dab75SAndroid Build Coastguard Worker   uint32_t bytes = 0;
166*5c4dab75SAndroid Build Coastguard Worker   while (bytes < len) {
167*5c4dab75SAndroid Build Coastguard Worker     ssize_t ret = read(handle->fd, (void *)(buf + bytes), len - bytes);
168*5c4dab75SAndroid Build Coastguard Worker     if (ret < 0) {
169*5c4dab75SAndroid Build Coastguard Worker       if (errno == EAGAIN || errno == EINTR) {
170*5c4dab75SAndroid Build Coastguard Worker         continue;
171*5c4dab75SAndroid Build Coastguard Worker       }
172*5c4dab75SAndroid Build Coastguard Worker       ALOGE("%s: failed to read from hw (ret=%zd, errno=%d)", __func__, ret,
173*5c4dab75SAndroid Build Coastguard Worker             errno);
174*5c4dab75SAndroid Build Coastguard Worker       ese_set_error(ese, kNxpPn80tErrorReceive);
175*5c4dab75SAndroid Build Coastguard Worker       return 0;
176*5c4dab75SAndroid Build Coastguard Worker     }
177*5c4dab75SAndroid Build Coastguard Worker     bytes += ret;
178*5c4dab75SAndroid Build Coastguard Worker   }
179*5c4dab75SAndroid Build Coastguard Worker   ALOGV("%s: read bytes: %u", __func__, bytes);
180*5c4dab75SAndroid Build Coastguard Worker   return len;
181*5c4dab75SAndroid Build Coastguard Worker }
182*5c4dab75SAndroid Build Coastguard Worker 
183*5c4dab75SAndroid Build Coastguard Worker static const struct Pn80tPlatform kPn80tNqNciPlatform = {
184*5c4dab75SAndroid Build Coastguard Worker     .initialize = &platform_init,
185*5c4dab75SAndroid Build Coastguard Worker     .release = &platform_release,
186*5c4dab75SAndroid Build Coastguard Worker     .toggle_reset = &platform_toggle_reset,
187*5c4dab75SAndroid Build Coastguard Worker     .toggle_ven = NULL,
188*5c4dab75SAndroid Build Coastguard Worker     .toggle_power_req = NULL,
189*5c4dab75SAndroid Build Coastguard Worker     .toggle_bootloader = &platform_toggle_bootloader,
190*5c4dab75SAndroid Build Coastguard Worker     .wait = &platform_wait,
191*5c4dab75SAndroid Build Coastguard Worker };
192*5c4dab75SAndroid Build Coastguard Worker 
193*5c4dab75SAndroid Build Coastguard Worker static const struct EseOperations ops = {
194*5c4dab75SAndroid Build Coastguard Worker     .name = "NXP PN80T/PN81A (NQ-NCI:PN553)",
195*5c4dab75SAndroid Build Coastguard Worker     .open = &nxp_pn80t_open,
196*5c4dab75SAndroid Build Coastguard Worker     .hw_receive = &nq_receive,
197*5c4dab75SAndroid Build Coastguard Worker     .hw_transmit = &nq_transmit,
198*5c4dab75SAndroid Build Coastguard Worker     .hw_reset = &nxp_pn80t_reset,
199*5c4dab75SAndroid Build Coastguard Worker     .transceive = &nxp_pn80t_transceive,
200*5c4dab75SAndroid Build Coastguard Worker     .poll = &nxp_pn80t_poll,
201*5c4dab75SAndroid Build Coastguard Worker     .close = &nxp_pn80t_close,
202*5c4dab75SAndroid Build Coastguard Worker     .opts = &kPn80tNqNciPlatform,
203*5c4dab75SAndroid Build Coastguard Worker     .errors = kNxpPn80tErrorMessages,
204*5c4dab75SAndroid Build Coastguard Worker     .errors_count = kNxpPn80tErrorMax,
205*5c4dab75SAndroid Build Coastguard Worker };
206*5c4dab75SAndroid Build Coastguard Worker __attribute__((visibility("default")))
207*5c4dab75SAndroid Build Coastguard Worker ESE_DEFINE_HW_OPS(ESE_HW_NXP_PN80T_NQ_NCI, ops);
208