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