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 * Defines the PN80T spidev device and platform wrappers consumed in
17*5c4dab75SAndroid Build Coastguard Worker * the common code.
18*5c4dab75SAndroid Build Coastguard Worker */
19*5c4dab75SAndroid Build Coastguard Worker
20*5c4dab75SAndroid Build Coastguard Worker #include <fcntl.h>
21*5c4dab75SAndroid Build Coastguard Worker #include <limits.h>
22*5c4dab75SAndroid Build Coastguard Worker #include <linux/spi/spidev.h>
23*5c4dab75SAndroid Build Coastguard Worker #include <stdint.h>
24*5c4dab75SAndroid Build Coastguard Worker #include <stdio.h>
25*5c4dab75SAndroid Build Coastguard Worker #include <stdlib.h>
26*5c4dab75SAndroid Build Coastguard Worker #include <string.h>
27*5c4dab75SAndroid Build Coastguard Worker #include <sys/ioctl.h>
28*5c4dab75SAndroid Build Coastguard Worker #include <unistd.h>
29*5c4dab75SAndroid Build Coastguard Worker
30*5c4dab75SAndroid Build Coastguard Worker #include "../include/ese/hw/nxp/pn80t/common.h"
31*5c4dab75SAndroid Build Coastguard Worker #include "../include/ese/hw/nxp/spi_board.h"
32*5c4dab75SAndroid Build Coastguard Worker
33*5c4dab75SAndroid Build Coastguard Worker struct Handle {
34*5c4dab75SAndroid Build Coastguard Worker int spi_fd;
35*5c4dab75SAndroid Build Coastguard Worker struct NxpSpiBoard *board;
36*5c4dab75SAndroid Build Coastguard Worker };
37*5c4dab75SAndroid Build Coastguard Worker
gpio_set(int num,int val)38*5c4dab75SAndroid Build Coastguard Worker int gpio_set(int num, int val) {
39*5c4dab75SAndroid Build Coastguard Worker char val_path[256];
40*5c4dab75SAndroid Build Coastguard Worker char val_chr = (val ? '1' : '0');
41*5c4dab75SAndroid Build Coastguard Worker int fd;
42*5c4dab75SAndroid Build Coastguard Worker if (num < 0) {
43*5c4dab75SAndroid Build Coastguard Worker return 0;
44*5c4dab75SAndroid Build Coastguard Worker }
45*5c4dab75SAndroid Build Coastguard Worker if (snprintf(val_path, sizeof(val_path), "/sys/class/gpio/gpio%d/value",
46*5c4dab75SAndroid Build Coastguard Worker num) >= (int)sizeof(val_path)) {
47*5c4dab75SAndroid Build Coastguard Worker return -1;
48*5c4dab75SAndroid Build Coastguard Worker }
49*5c4dab75SAndroid Build Coastguard Worker printf("Gpio @ %s\n", val_path);
50*5c4dab75SAndroid Build Coastguard Worker fd = open(val_path, O_WRONLY);
51*5c4dab75SAndroid Build Coastguard Worker if (fd < 0) {
52*5c4dab75SAndroid Build Coastguard Worker return -1;
53*5c4dab75SAndroid Build Coastguard Worker }
54*5c4dab75SAndroid Build Coastguard Worker if (write(fd, &val_chr, 1) < 0) {
55*5c4dab75SAndroid Build Coastguard Worker close(fd);
56*5c4dab75SAndroid Build Coastguard Worker return -1;
57*5c4dab75SAndroid Build Coastguard Worker }
58*5c4dab75SAndroid Build Coastguard Worker close(fd);
59*5c4dab75SAndroid Build Coastguard Worker return 0;
60*5c4dab75SAndroid Build Coastguard Worker }
61*5c4dab75SAndroid Build Coastguard Worker
platform_toggle_ven(void * blob,int val)62*5c4dab75SAndroid Build Coastguard Worker int platform_toggle_ven(void *blob, int val) {
63*5c4dab75SAndroid Build Coastguard Worker struct Handle *handle = blob;
64*5c4dab75SAndroid Build Coastguard Worker printf("Toggling VEN: %d\n", val);
65*5c4dab75SAndroid Build Coastguard Worker return gpio_set(handle->board->gpios[kBoardGpioNfcVen], val);
66*5c4dab75SAndroid Build Coastguard Worker }
67*5c4dab75SAndroid Build Coastguard Worker
platform_toggle_reset(void * blob,int val)68*5c4dab75SAndroid Build Coastguard Worker int platform_toggle_reset(void *blob, int val) {
69*5c4dab75SAndroid Build Coastguard Worker struct Handle *handle = blob;
70*5c4dab75SAndroid Build Coastguard Worker printf("Toggling RST: %d\n", val);
71*5c4dab75SAndroid Build Coastguard Worker return gpio_set(handle->board->gpios[kBoardGpioEseRst], val);
72*5c4dab75SAndroid Build Coastguard Worker }
73*5c4dab75SAndroid Build Coastguard Worker
platform_toggle_power_req(void * blob,int val)74*5c4dab75SAndroid Build Coastguard Worker int platform_toggle_power_req(void *blob, int val) {
75*5c4dab75SAndroid Build Coastguard Worker struct Handle *handle = blob;
76*5c4dab75SAndroid Build Coastguard Worker printf("Toggling SVDD_PWR_REQ: %d\n", val);
77*5c4dab75SAndroid Build Coastguard Worker return gpio_set(handle->board->gpios[kBoardGpioEseSvddPwrReq], val);
78*5c4dab75SAndroid Build Coastguard Worker }
79*5c4dab75SAndroid Build Coastguard Worker
gpio_configure(int num,int out,int val)80*5c4dab75SAndroid Build Coastguard Worker int gpio_configure(int num, int out, int val) {
81*5c4dab75SAndroid Build Coastguard Worker char dir_path[256];
82*5c4dab75SAndroid Build Coastguard Worker char numstr[8];
83*5c4dab75SAndroid Build Coastguard Worker char dir[5];
84*5c4dab75SAndroid Build Coastguard Worker int fd;
85*5c4dab75SAndroid Build Coastguard Worker /* <0 is unmapped. No work to do! */
86*5c4dab75SAndroid Build Coastguard Worker if (num < 0) {
87*5c4dab75SAndroid Build Coastguard Worker return 0;
88*5c4dab75SAndroid Build Coastguard Worker }
89*5c4dab75SAndroid Build Coastguard Worker if (snprintf(dir, sizeof(dir), "%s", (out ? "out" : "in")) >=
90*5c4dab75SAndroid Build Coastguard Worker (int)sizeof(dir)) {
91*5c4dab75SAndroid Build Coastguard Worker return -1;
92*5c4dab75SAndroid Build Coastguard Worker }
93*5c4dab75SAndroid Build Coastguard Worker if (snprintf(dir_path, sizeof(dir_path), "/sys/class/gpio/gpio%d/direction",
94*5c4dab75SAndroid Build Coastguard Worker num) >= (int)sizeof(dir_path)) {
95*5c4dab75SAndroid Build Coastguard Worker return -1;
96*5c4dab75SAndroid Build Coastguard Worker }
97*5c4dab75SAndroid Build Coastguard Worker if (snprintf(numstr, sizeof(numstr), "%d", num) >= (int)sizeof(numstr)) {
98*5c4dab75SAndroid Build Coastguard Worker return -1;
99*5c4dab75SAndroid Build Coastguard Worker }
100*5c4dab75SAndroid Build Coastguard Worker fd = open("/sys/class/gpio/export", O_WRONLY);
101*5c4dab75SAndroid Build Coastguard Worker if (fd < 0) {
102*5c4dab75SAndroid Build Coastguard Worker return -1;
103*5c4dab75SAndroid Build Coastguard Worker }
104*5c4dab75SAndroid Build Coastguard Worker /* Exporting can only happen once, so instead of stat()ing, just ignore
105*5c4dab75SAndroid Build Coastguard Worker * errors. */
106*5c4dab75SAndroid Build Coastguard Worker (void)write(fd, numstr, strlen(numstr));
107*5c4dab75SAndroid Build Coastguard Worker close(fd);
108*5c4dab75SAndroid Build Coastguard Worker
109*5c4dab75SAndroid Build Coastguard Worker fd = open(dir_path, O_WRONLY);
110*5c4dab75SAndroid Build Coastguard Worker if (fd < 0) {
111*5c4dab75SAndroid Build Coastguard Worker return -1;
112*5c4dab75SAndroid Build Coastguard Worker }
113*5c4dab75SAndroid Build Coastguard Worker if (write(fd, dir, strlen(dir)) < 0) {
114*5c4dab75SAndroid Build Coastguard Worker close(fd);
115*5c4dab75SAndroid Build Coastguard Worker return -1;
116*5c4dab75SAndroid Build Coastguard Worker }
117*5c4dab75SAndroid Build Coastguard Worker close(fd);
118*5c4dab75SAndroid Build Coastguard Worker return gpio_set(num, val);
119*5c4dab75SAndroid Build Coastguard Worker }
120*5c4dab75SAndroid Build Coastguard Worker
platform_init(void * hwopts)121*5c4dab75SAndroid Build Coastguard Worker void *platform_init(void *hwopts) {
122*5c4dab75SAndroid Build Coastguard Worker struct NxpSpiBoard *board = hwopts;
123*5c4dab75SAndroid Build Coastguard Worker struct Handle *handle;
124*5c4dab75SAndroid Build Coastguard Worker int gpio = 0;
125*5c4dab75SAndroid Build Coastguard Worker
126*5c4dab75SAndroid Build Coastguard Worker handle = malloc(sizeof(*handle));
127*5c4dab75SAndroid Build Coastguard Worker if (!handle) {
128*5c4dab75SAndroid Build Coastguard Worker return NULL;
129*5c4dab75SAndroid Build Coastguard Worker }
130*5c4dab75SAndroid Build Coastguard Worker handle->board = board;
131*5c4dab75SAndroid Build Coastguard Worker
132*5c4dab75SAndroid Build Coastguard Worker /* Initialize the mapped GPIOs */
133*5c4dab75SAndroid Build Coastguard Worker for (; gpio < kBoardGpioMax; ++gpio) {
134*5c4dab75SAndroid Build Coastguard Worker if (gpio_configure(board->gpios[gpio], 1, 1) < 0) {
135*5c4dab75SAndroid Build Coastguard Worker free(handle);
136*5c4dab75SAndroid Build Coastguard Worker return NULL;
137*5c4dab75SAndroid Build Coastguard Worker }
138*5c4dab75SAndroid Build Coastguard Worker }
139*5c4dab75SAndroid Build Coastguard Worker
140*5c4dab75SAndroid Build Coastguard Worker handle->spi_fd = open(board->dev_path, O_RDWR);
141*5c4dab75SAndroid Build Coastguard Worker if (handle->spi_fd < 0) {
142*5c4dab75SAndroid Build Coastguard Worker free(handle);
143*5c4dab75SAndroid Build Coastguard Worker return NULL;
144*5c4dab75SAndroid Build Coastguard Worker }
145*5c4dab75SAndroid Build Coastguard Worker /* If we need anything fancier, we'll need MODE32 in the headers. */
146*5c4dab75SAndroid Build Coastguard Worker if (ioctl(handle->spi_fd, SPI_IOC_WR_MODE, &board->mode) < 0) {
147*5c4dab75SAndroid Build Coastguard Worker close(handle->spi_fd);
148*5c4dab75SAndroid Build Coastguard Worker free(handle);
149*5c4dab75SAndroid Build Coastguard Worker return NULL;
150*5c4dab75SAndroid Build Coastguard Worker }
151*5c4dab75SAndroid Build Coastguard Worker if (ioctl(handle->spi_fd, SPI_IOC_WR_BITS_PER_WORD, &board->bits) < 0) {
152*5c4dab75SAndroid Build Coastguard Worker close(handle->spi_fd);
153*5c4dab75SAndroid Build Coastguard Worker free(handle);
154*5c4dab75SAndroid Build Coastguard Worker return NULL;
155*5c4dab75SAndroid Build Coastguard Worker }
156*5c4dab75SAndroid Build Coastguard Worker if (ioctl(handle->spi_fd, SPI_IOC_WR_MAX_SPEED_HZ, &board->speed) < 0) {
157*5c4dab75SAndroid Build Coastguard Worker close(handle->spi_fd);
158*5c4dab75SAndroid Build Coastguard Worker free(handle);
159*5c4dab75SAndroid Build Coastguard Worker return NULL;
160*5c4dab75SAndroid Build Coastguard Worker }
161*5c4dab75SAndroid Build Coastguard Worker printf("Linux SPIDev initialized\n");
162*5c4dab75SAndroid Build Coastguard Worker return (void *)handle;
163*5c4dab75SAndroid Build Coastguard Worker }
164*5c4dab75SAndroid Build Coastguard Worker
platform_release(void * blob)165*5c4dab75SAndroid Build Coastguard Worker int platform_release(void *blob) {
166*5c4dab75SAndroid Build Coastguard Worker struct Handle *handle = blob;
167*5c4dab75SAndroid Build Coastguard Worker close(handle->spi_fd);
168*5c4dab75SAndroid Build Coastguard Worker free(handle);
169*5c4dab75SAndroid Build Coastguard Worker /* Note, we don't unconfigure the GPIOs. */
170*5c4dab75SAndroid Build Coastguard Worker return 0;
171*5c4dab75SAndroid Build Coastguard Worker }
172*5c4dab75SAndroid Build Coastguard Worker
platform_wait(void * blob,long usec)173*5c4dab75SAndroid Build Coastguard Worker int platform_wait(void *blob __attribute__((unused)), long usec) {
174*5c4dab75SAndroid Build Coastguard Worker return usleep((useconds_t)usec);
175*5c4dab75SAndroid Build Coastguard Worker }
176*5c4dab75SAndroid Build Coastguard Worker
spidev_transmit(struct EseInterface * ese,const uint8_t * buf,uint32_t len,int complete)177*5c4dab75SAndroid Build Coastguard Worker uint32_t spidev_transmit(struct EseInterface *ese, const uint8_t *buf,
178*5c4dab75SAndroid Build Coastguard Worker uint32_t len, int complete) {
179*5c4dab75SAndroid Build Coastguard Worker struct NxpState *ns = NXP_PN80T_STATE(ese);
180*5c4dab75SAndroid Build Coastguard Worker struct Handle *handle = ns->handle;
181*5c4dab75SAndroid Build Coastguard Worker struct spi_ioc_transfer tr = {
182*5c4dab75SAndroid Build Coastguard Worker .tx_buf = (unsigned long)buf,
183*5c4dab75SAndroid Build Coastguard Worker .rx_buf = 0,
184*5c4dab75SAndroid Build Coastguard Worker .len = (uint32_t)len,
185*5c4dab75SAndroid Build Coastguard Worker .delay_usecs = 0,
186*5c4dab75SAndroid Build Coastguard Worker .speed_hz = 0,
187*5c4dab75SAndroid Build Coastguard Worker .bits_per_word = 0,
188*5c4dab75SAndroid Build Coastguard Worker .cs_change = !!complete,
189*5c4dab75SAndroid Build Coastguard Worker };
190*5c4dab75SAndroid Build Coastguard Worker ssize_t ret = -1;
191*5c4dab75SAndroid Build Coastguard Worker ALOGV("spidev:%s: called [%d]", __func__, len);
192*5c4dab75SAndroid Build Coastguard Worker if (len > INT_MAX) {
193*5c4dab75SAndroid Build Coastguard Worker ese_set_error(ese, kNxpPn80tErrorTransmitSize);
194*5c4dab75SAndroid Build Coastguard Worker ALOGE("Unexpectedly large transfer attempted: %u", len);
195*5c4dab75SAndroid Build Coastguard Worker return 0;
196*5c4dab75SAndroid Build Coastguard Worker }
197*5c4dab75SAndroid Build Coastguard Worker ret = ioctl(handle->spi_fd, SPI_IOC_MESSAGE(1), &tr);
198*5c4dab75SAndroid Build Coastguard Worker if (ret < 1) {
199*5c4dab75SAndroid Build Coastguard Worker ese_set_error(ese, kNxpPn80tErrorTransmit);
200*5c4dab75SAndroid Build Coastguard Worker ALOGE("%s: failed to write to hw (ret=%zd)", __func__, ret);
201*5c4dab75SAndroid Build Coastguard Worker return 0;
202*5c4dab75SAndroid Build Coastguard Worker }
203*5c4dab75SAndroid Build Coastguard Worker return len;
204*5c4dab75SAndroid Build Coastguard Worker }
205*5c4dab75SAndroid Build Coastguard Worker
spidev_receive(struct EseInterface * ese,uint8_t * buf,uint32_t len,int complete)206*5c4dab75SAndroid Build Coastguard Worker uint32_t spidev_receive(struct EseInterface *ese, uint8_t *buf, uint32_t len,
207*5c4dab75SAndroid Build Coastguard Worker int complete) {
208*5c4dab75SAndroid Build Coastguard Worker struct NxpState *ns = NXP_PN80T_STATE(ese);
209*5c4dab75SAndroid Build Coastguard Worker struct Handle *handle = ns->handle;
210*5c4dab75SAndroid Build Coastguard Worker ssize_t ret = -1;
211*5c4dab75SAndroid Build Coastguard Worker struct spi_ioc_transfer tr = {
212*5c4dab75SAndroid Build Coastguard Worker .tx_buf = 0,
213*5c4dab75SAndroid Build Coastguard Worker .rx_buf = (unsigned long)buf,
214*5c4dab75SAndroid Build Coastguard Worker .len = (uint32_t)len,
215*5c4dab75SAndroid Build Coastguard Worker .delay_usecs = 0,
216*5c4dab75SAndroid Build Coastguard Worker .speed_hz = 0,
217*5c4dab75SAndroid Build Coastguard Worker .bits_per_word = 0,
218*5c4dab75SAndroid Build Coastguard Worker .cs_change = !!complete,
219*5c4dab75SAndroid Build Coastguard Worker };
220*5c4dab75SAndroid Build Coastguard Worker ALOGV("spidev:%s: called [%d]", __func__, len);
221*5c4dab75SAndroid Build Coastguard Worker if (len > INT_MAX) {
222*5c4dab75SAndroid Build Coastguard Worker ese_set_error(ese, kNxpPn80tErrorReceiveSize);
223*5c4dab75SAndroid Build Coastguard Worker ALOGE("Unexpectedly large receive attempted: %u", len);
224*5c4dab75SAndroid Build Coastguard Worker return 0;
225*5c4dab75SAndroid Build Coastguard Worker }
226*5c4dab75SAndroid Build Coastguard Worker ret = ioctl(handle->spi_fd, SPI_IOC_MESSAGE(1), &tr);
227*5c4dab75SAndroid Build Coastguard Worker if (ret < 1) {
228*5c4dab75SAndroid Build Coastguard Worker ALOGE("%s: failed to read from hw (ret=%zd)", __func__, ret);
229*5c4dab75SAndroid Build Coastguard Worker ese_set_error(ese, kNxpPn80tErrorReceive);
230*5c4dab75SAndroid Build Coastguard Worker return 0;
231*5c4dab75SAndroid Build Coastguard Worker }
232*5c4dab75SAndroid Build Coastguard Worker ALOGV("%s: read bytes: %zd", __func__, len);
233*5c4dab75SAndroid Build Coastguard Worker return len;
234*5c4dab75SAndroid Build Coastguard Worker }
235*5c4dab75SAndroid Build Coastguard Worker
236*5c4dab75SAndroid Build Coastguard Worker static const struct Pn80tPlatform kPn80tLinuxSpidevPlatform = {
237*5c4dab75SAndroid Build Coastguard Worker .initialize = &platform_init,
238*5c4dab75SAndroid Build Coastguard Worker .release = &platform_release,
239*5c4dab75SAndroid Build Coastguard Worker .toggle_reset = &platform_toggle_reset,
240*5c4dab75SAndroid Build Coastguard Worker .toggle_ven = &platform_toggle_ven,
241*5c4dab75SAndroid Build Coastguard Worker .toggle_power_req = &platform_toggle_power_req,
242*5c4dab75SAndroid Build Coastguard Worker .toggle_bootloader = NULL,
243*5c4dab75SAndroid Build Coastguard Worker .wait = &platform_wait,
244*5c4dab75SAndroid Build Coastguard Worker };
245*5c4dab75SAndroid Build Coastguard Worker
246*5c4dab75SAndroid Build Coastguard Worker static const struct EseOperations ops = {
247*5c4dab75SAndroid Build Coastguard Worker .name = "NXP PN80T/PN81A (PN553)",
248*5c4dab75SAndroid Build Coastguard Worker .open = &nxp_pn80t_open,
249*5c4dab75SAndroid Build Coastguard Worker .hw_receive = &spidev_receive,
250*5c4dab75SAndroid Build Coastguard Worker .hw_transmit = &spidev_transmit,
251*5c4dab75SAndroid Build Coastguard Worker .hw_reset = &nxp_pn80t_reset,
252*5c4dab75SAndroid Build Coastguard Worker .transceive = &nxp_pn80t_transceive,
253*5c4dab75SAndroid Build Coastguard Worker .poll = &nxp_pn80t_poll,
254*5c4dab75SAndroid Build Coastguard Worker .close = &nxp_pn80t_close,
255*5c4dab75SAndroid Build Coastguard Worker .opts = &kPn80tLinuxSpidevPlatform,
256*5c4dab75SAndroid Build Coastguard Worker .errors = kNxpPn80tErrorMessages,
257*5c4dab75SAndroid Build Coastguard Worker .errors_count = kNxpPn80tErrorMax,
258*5c4dab75SAndroid Build Coastguard Worker };
259*5c4dab75SAndroid Build Coastguard Worker __attribute__((visibility("default")))
260*5c4dab75SAndroid Build Coastguard Worker ESE_DEFINE_HW_OPS(ESE_HW_NXP_PN80T_SPIDEV, ops);
261