1 /*
2 * Copyright (C) 2022 HiSilicon (Shanghai) Technologies CO., LIMITED.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18
19 #include <asm/io.h>
20 #include <asm/irq.h>
21 #include <asm/uaccess.h>
22
23 #include <linux/delay.h>
24 #include <linux/module.h>
25 #include <linux/kernel.h>
26 #include <linux/types.h>
27 #include <linux/fs.h>
28 #include <linux/errno.h>
29 #include <linux/miscdevice.h>
30 #include <linux/fcntl.h>
31 #include <linux/init.h>
32 #include <linux/proc_fs.h>
33 #include <linux/slab.h>
34 #include <linux/string.h>
35 #include <linux/i2c.h>
36
37 #include "hi_drv_i2c.h"
38 #include "hi_osal.h"
39 #include "hi_module.h"
40 #include "hi_drv_gpio.h"
41 #include "fm11nt081d.h"
42
43 #define NFC_EEPROM_BASE_ADDR (0x0010)
44 #define NFC_EEPROM_FINALY_ADDR (0x0384)
45 #define NFC_CMD_LEN (2)
46 #define NFC_WECHAT_NDEF_LEN (34)
47 #define READ_NFC_WECHAT_NDEF_LEN (50)
48 #define NFC_TOUTIAO_NDEF_LEN (47)
49 #define READ_NFC_TOUTIAO_NDEF_LEN (63)
50 #define NFC_EERROM_READ_BUFF_LEN_MAX (888)
51 #define NFC_CSN_GPIO_NUM (44) // GPIO5_4 5*8+4 = 44
52
53 #define C081_NFC_ADDR (0xAE)
54 #define I2C_WR (0x00)
55 #define I2C_RD (0x01)
56 #define C081_NFC_WRITE_ADDR (C081_NFC_ADDR|I2C_WR)
57 #define C081_NFC_READ_ADDR (C081_NFC_ADDR|I2C_RD)
58 #define FM11_E2_USER_ADDR (0x0010)
59 #define FM11_E2_MAUNF_ADDR (0x03FF)
60 #define FM11_E2_BLOCK_SIZE (16)
61 #define DEFAULT_MD_LEN (128)
62 #define RIGHR_MOVE_8_BIT (8)
63 #define NFC_NDEF_MAX_LEN (888)
64
65 #define LOW_LEVEL 0
66 #define HIGH_LEVEL 1
67 #define I2C1_SDA 0x03
68 #define I2C1_SCL 0x03
69 #define GPIO5_4 0xF8A2149C
70 #define CSN_DOWN 0x0
71 #define GPIO0_4 0xF8A21000
72 #define GPIO0_5 0xF8A21004
73
74 static struct miscdevice nfc_miscdevice = { 0, };
75 hi_u8 wbuf[5] = {0x05, 0x78, 0xF7, 0x90, 0x02};
76
77 i2c_ext_func *i2c_func = HI_NULL;
78 gpio_ext_func *g_gpio_func = HI_NULL;
79
80 typedef enum {
81 I2C_CHANNEL_0 = 0,
82 I2C_CHANNEL_1 = 1
83 } i2c_channel_def;
84
C081NfcI2cWrite(hi_u16 cmd,hi_u8 * data_buff,hi_u8 len)85 static hi_u32 C081NfcI2cWrite(hi_u16 cmd, hi_u8 *data_buff, hi_u8 len)
86 {
87 hi_u32 status = 0;
88 hi_u32 ret = 0;
89 hi_u32 id = I2C_CHANNEL_1;
90
91 if (i2c_func == HI_NULL) {
92 NFC_ERR("HI_ID_ I2C handle get failed \r\n");
93 return HI_FAILURE;
94 }
95
96 if (data_buff == HI_NULL) {
97 NFC_ERR("C081NfcI2cWrite data is null\r\n");
98 }
99
100 status = i2c_func->pfn_i2c_write(id, C081_NFC_ADDR & 0xFE, cmd, NFC_CMD_LEN, data_buff, len);
101 if (status != 0) {
102 return HI_FAILURE;
103 }
104
105 return 0;
106 }
107
PullSetCsn(hi_s32 level)108 static hi_void PullSetCsn(hi_s32 level)
109 {
110 g_gpio_func->pfn_gpio_write_bit(NFC_CSN_GPIO_NUM, level);
111 }
112
EepWritePage(hi_u8 * pBuffer,hi_u16 writeAddr,hi_u8 dataLen)113 static hi_void EepWritePage(hi_u8 *pBuffer, hi_u16 writeAddr, hi_u8 dataLen)
114 {
115 hi_u32 status;
116 if (pBuffer == NULL) {
117 NFC_ERR("eepWritePage buffer is null\r\n");
118 }
119 PullSetCsn(LOW_LEVEL);
120 status = C081NfcI2cWrite(writeAddr, pBuffer, dataLen);
121 msleep(10); // The delay time must be 10ms
122 PullSetCsn(HIGH_LEVEL);
123 }
124
Fm11nt081dWriteEeprom(hi_u16 baseAddr,hi_u32 len,hi_u8 * wbuf)125 static hi_void Fm11nt081dWriteEeprom(hi_u16 baseAddr, hi_u32 len, hi_u8 *wbuf)
126 {
127 hi_u8 offset = 0;
128 hi_u8 *writeBuff = wbuf;
129 hi_u32 writeLen = len;
130 hi_u16 addr = baseAddr;
131
132 if (writeBuff == NULL) {
133 NFC_ERR("write ndef is null\r\n");
134 return;
135 }
136
137 if (addr < FM11_E2_USER_ADDR || addr >= FM11_E2_MAUNF_ADDR) {
138 offset = FM11_E2_BLOCK_SIZE - (addr % FM11_E2_BLOCK_SIZE);
139 NFC_ERR("offset = %d, writeLen = %d\r\n", offset, writeLen);
140 if (writeLen > offset) {
141 EepWritePage(writeBuff, addr, offset);
142 addr += offset;
143 writeBuff += offset;
144 writeLen -= offset;
145 } else {
146 EepWritePage(writeBuff, addr, writeLen);
147 writeLen = 0;
148 }
149 }
150 while (writeLen) {
151 if (writeLen >= FM11_E2_BLOCK_SIZE) {
152 EepWritePage(writeBuff, addr, FM11_E2_BLOCK_SIZE);
153 addr += FM11_E2_BLOCK_SIZE;
154 writeBuff += FM11_E2_BLOCK_SIZE;
155 writeLen -= FM11_E2_BLOCK_SIZE;
156 } else {
157 EepWritePage(writeBuff, addr, writeLen);
158 writeLen = 0;
159 }
160 }
161 }
162
WriteRead(hi_u16 cmd,hi_u8 send_len,hi_u8 read_len)163 static hi_u32 WriteRead(hi_u16 cmd, hi_u8 send_len, hi_u8 read_len)
164 {
165 hi_u32 i = 0;
166 hi_u32 ret = 0;
167 hi_u32 status = 0;
168 hi_u32 id = I2C_CHANNEL_1;
169 hi_u8 recvData[888] = {0};
170
171 if (i2c_func == HI_NULL) {
172 NFC_ERR("HI_ID_I2C handle get failed \r\n");
173 return HI_FAILURE;
174 }
175
176 status = i2c_func->pfn_i2c_read(id, C081_NFC_ADDR | I2C_RD, cmd, send_len, recvData, read_len);
177 if (status != 0) {
178 return HI_FAILURE;
179 }
180
181 NFC_INFO("<Fm11nt081d>: read ndef data\r\n");
182
183 for (i = 0; i < read_len; i++) {
184 NFC_ERR("0x%x ", recvData[i]);
185 }
186
187 NFC_INFO("\r\n");
188 return 0;
189 }
190
Fm11nt081ReadEep(hi_u16 readAddr,hi_u16 len)191 static hi_u32 Fm11nt081ReadEep(hi_u16 readAddr, hi_u16 len)
192 {
193 hi_u32 status;
194
195 status = WriteRead(readAddr, NFC_CMD_LEN, len);
196 if (status != 0) {
197 return HI_FAILURE;
198 }
199 return 0;
200 }
201
202 static const struct i2c_device_id nfc_id[] = {
203 {"ft", 0},
204 {}
205 };
206
207 MODULE_DEVICE_TABLE(i2c, nfc_id);
208
Fm11nt081dSetReg(hi_u32 addr,hi_u32 value)209 static hi_s32 Fm11nt081dSetReg(hi_u32 addr, hi_u32 value)
210 {
211 void* pmem = ioremap(addr, DEFAULT_MD_LEN);
212
213 if (pmem == HI_NULL) {
214 return HI_FAILURE;
215 }
216
217 *(hi_u32*)pmem = value;
218 iounmap(pmem);
219 return 0;
220 }
221
222 hi_u8 ndefFile[4][NFC_NDEF_MAX_LEN] = {
223 // wechat
224 {
225 0x03, 0x20,
226 0xd4, 0x0f, 0x0e, 0x61, 0x6e, 0x64, 0x72, 0x6f,
227 0x69, 0x64, 0x2e, 0x63, 0x6f, 0x6d, 0x3a, 0x70,
228 0x6b, 0x67, 0x63, 0x6f, 0x6d, 0x2e, 0x74, 0x65,
229 0x6e, 0x63, 0x65, 0x6e, 0x74, 0x2e, 0x6d, 0x6d,
230 },
231 // today headline
232 {
233 0x03, 0x2d,
234 0xd4, 0x0f, 0x1b, 0x61, 0x6e, 0x64, 0x72, 0x6f,
235 0x69, 0x64, 0x2e, 0x63, 0x6f, 0x6d, 0x3a, 0x70,
236 0x6b, 0x67, 0x63, 0x6f, 0x6d, 0x2e, 0x73, 0x63,
237 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64,
238 0x2e, 0x61, 0x72, 0x74, 0x69, 0x63, 0x6c, 0x65,
239 },
240 // taobao
241 {
242 0x03, 0x23,
243 0xd4, 0x0f, 0x11, 0x61, 0x6e, 0x64, 0x72, 0x6f,
244 0x69, 0x64, 0x2e, 0x63, 0x6f, 0x6d, 0x3a, 0x70,
245 0x6b, 0x67, 0x63, 0x6f, 0x6d, 0x2e, 0x74, 0x61,
246 0x6f, 0x62, 0x61, 0x6f, 0x2e, 0x74, 0x61, 0x6f,
247 0x62, 0x61, 0x6f,
248 },
249 // smart life
250 {
251 0x03, 0x26,
252 0xd4, 0x0f, 0x14, 0x61, 0x6e, 0x64, 0x72, 0x6f,
253 0x69, 0x64, 0x2e, 0x63, 0x6f, 0x6d, 0x3a, 0x70,
254 0x6b, 0x67, 0x63, 0x6f, 0x6d, 0x2e, 0x68, 0x75,
255 0x61, 0x77, 0x65, 0x69, 0x2e, 0x73, 0x6d, 0x61,
256 0x72, 0x74, 0x68, 0x6f, 0x6d, 0x65,
257 }
258 };
259
nfc_read_ep(hi_u8 * recvData)260 static hi_u32 nfc_read_ep(hi_u8 *recvData)
261 {
262 hi_u32 id = I2C_CHANNEL_1;
263 hi_u32 status = 0;
264 hi_s32 i;
265 hi_u32 ret = 0;
266
267 if (i2c_func == HI_NULL) {
268 NFC_ERR("HI_ID_I2C handle get failed \r\n");
269 return HI_FAILURE;
270 }
271
272 status = i2c_func->pfn_i2c_read(id, C081_NFC_ADDR | I2C_RD, NFC_EEPROM_BASE_ADDR, NFC_CMD_LEN, recvData,
273 NFC_TOUTIAO_NDEF_LEN);
274 if (status != 0) {
275 return HI_FAILURE;
276 }
277
278 NFC_INFO("<Fm11nt081d>: read ndef data\r\n");
279
280 for (i = 0; i < strlen(recvData); i++) {
281 NFC_ERR("0x%x ", recvData[i]);
282 }
283
284 NFC_INFO("\r\n");
285 return 0;
286 }
287
288
nfc_write_ep(hi_u8 * buf)289 hi_void nfc_write_ep(hi_u8 *buf)
290 {
291 Fm11nt081dWriteEeprom(0x3B1, 1, &wbuf[1]);
292 Fm11nt081dWriteEeprom(0x3B5, 1, &wbuf[3]); // 3 for index
293
294 /* write NFC EEPROM */
295 Fm11nt081dWriteEeprom(NFC_EEPROM_BASE_ADDR, NFC_TOUTIAO_NDEF_LEN, buf);
296 // csn pull down
297 PullSetCsn(LOW_LEVEL);
298 }
299
nfc_open(struct inode * inode,struct file * filp)300 static hi_s32 nfc_open(struct inode *inode, struct file *filp)
301 {
302 NFC_INFO("Enter nfc_open");
303 return HI_SUCCESS;
304 }
305
nfc_release(struct inode * inode,struct file * filp)306 static hi_s32 nfc_release(struct inode *inode, struct file *filp)
307 {
308 NFC_INFO("Enter nfc_release");
309 return HI_SUCCESS;
310 }
311
312 #ifdef HAVE_UNLOCKED_IOCTL
nfc_ioctl(struct file * filp,hi_u32 cmd,unsigned long arg)313 static long nfc_ioctl(struct file *filp, hi_u32 cmd, unsigned long arg)
314 #else
315 static hi_s32 nfc_ioctl(struct inode *inode, struct file *filp, hi_u32 cmd, unsigned long arg)
316 #endif
317 {
318 hi_s32 ret = 0;
319 hi_char data_buf[120];
320
321 if (_IOC_TYPE(cmd) != HI_ID_NFC)
322 return -EINVAL;
323
324 if (_IOC_NR(cmd) > NFC_MAX_CMD)
325 return -EINVAL;
326
327 switch (cmd) {
328 case NFC_READ:
329 nfc_read_ep(data_buf);
330 ret = copy_to_user((hi_char __user *)arg, data_buf, sizeof(data_buf));
331 if (ret) {
332 ret = -EFAULT;
333 }
334 NFC_INFO("io ctl read_led: %d", strlen(data_buf));
335 break;
336 case NFC_WRITE:
337 ret = copy_from_user(data_buf, (hi_char __user *)arg, sizeof(data_buf));
338 if (ret) {
339 ret = -EFAULT;
340 }
341 nfc_write_ep(data_buf);
342 break;
343 default:
344 ret = -EFAULT;
345 }
346 return ret;
347 }
348
nfc_read(struct file * filp,hi_char __user * buf,size_t size,loff_t * offset)349 static ssize_t nfc_read(struct file *filp, hi_char __user *buf, size_t size, loff_t *offset)
350 {
351 hi_s32 ret;
352 hi_char recv_msg[20];
353 ret = copy_to_user(buf, recv_msg, size);
354 NFC_INFO("nfc_read: %s, %d", buf, size);
355
356 if (ret < 0) {
357 return -EFAULT;
358 }
359 return ret;
360 }
361
nfc_write(struct file * filp,const hi_char * buf,size_t size,loff_t * offset)362 static ssize_t nfc_write(struct file *filp, const hi_char *buf, size_t size, loff_t *offset)
363 {
364 hi_s32 ret;
365 hi_char send_msg[20];
366 ret = copy_from_user(send_msg, buf, size);
367 if (ret < 0) {
368 return -EFAULT;
369 }
370 return ret;
371 }
372
373 struct file_operations nfc_fops = {
374 .owner = THIS_MODULE,
375 .open = nfc_open,
376 .release = nfc_release,
377 #ifdef HAVE_UNLOCKED_IOCTL
378 .unlocked_ioctl = nfc_ioctl,
379 #else
380 .ioctl = nfc_ioctl,
381 #endif
382 .read = nfc_read,
383 .write = nfc_write,
384 };
385
fm11nt081d_init(hi_void)386 static hi_s32 __init fm11nt081d_init(hi_void)
387 {
388 hi_s32 ret = 0;
389 NFC_INFO("-----------------fm11nt081d_init-----------\n");
390
391 // fm11nt081d NFC GPIO configure
392 Fm11nt081dSetReg(GPIO5_4, CSN_DOWN);
393 Fm11nt081dSetReg(GPIO0_4, I2C1_SDA);
394 Fm11nt081dSetReg(GPIO5_4, I2C1_SCL);
395
396 gpio_drv_get_gpio_ext_func(&g_gpio_func);
397 if (g_gpio_func == HI_NULL) {
398 NFC_ERR("get gpio export function failed!\n");
399 return -EFAULT;
400 }
401
402 /* set GPIO to be output and low level */
403 g_gpio_func->pfn_gpio_dir_set_bit(NFC_CSN_GPIO_NUM, LOW_LEVEL);
404 g_gpio_func->pfn_gpio_write_bit(NFC_CSN_GPIO_NUM, LOW_LEVEL);
405
406 /* i2c_1 init */
407 ret = hi_drv_i2c_init();
408 if (ret) {
409 NFC_ERR("I2C init failed : %d\n", ret);
410 return -EFAULT;
411 }
412 i2c_drv_get_i2c_ext_func(&i2c_func);
413 if (i2c_func == HI_NULL) {
414 NFC_ERR("HI_ID_I2C handle get failed \r\n");
415 return -EFAULT;
416 }
417
418 nfc_miscdevice.minor = MISC_DYNAMIC_MINOR;
419 nfc_miscdevice.name = HINFC_DEVICE_NAME;
420 nfc_miscdevice.fops = &nfc_fops;
421
422 ret = misc_register(&nfc_miscdevice);
423 if (ret != 0) {
424 NFC_ERR("[%s, line: %d]Error: can't register\n", "NFC", __LINE__);
425 return -EFAULT;
426 }
427 return 0;
428 }
429
fm11nt081d_exit(hi_void)430 static hi_void __exit fm11nt081d_exit(hi_void)
431 {
432 NFC_INFO("-----------------fm11nt081d_exit-----------\n");
433 hi_drv_i2c_de_init();
434
435 misc_deregister(&nfc_miscdevice);
436 }
437 module_init(fm11nt081d_init);
438 module_exit(fm11nt081d_exit);
439
440 MODULE_LICENSE("GPL");
441 MODULE_AUTHOR("hisilicon");
442