xref: /aosp_15_r20/external/libese/libese-hw/nxp/pn80t/linux_spidev.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  * 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