1 /** 2 * Marvell NFC-over-UART driver 3 * 4 * Copyright (C) 2015, Marvell International Ltd. 5 * 6 * This software file (the "File") is distributed by Marvell International 7 * Ltd. under the terms of the GNU General Public License Version 2, June 1991 8 * (the "License"). You may use, redistribute and/or modify this File in 9 * accordance with the terms and conditions of the License, a copy of which 10 * is available on the worldwide web at 11 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. 12 * 13 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 14 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 15 * ARE EXPRESSLY DISCLAIMED. The License provides additional details about 16 * this warranty disclaimer. 17 */ 18 19 #include <linux/module.h> 20 #include <linux/delay.h> 21 #include <linux/of_gpio.h> 22 #include <net/nfc/nci.h> 23 #include <net/nfc/nci_core.h> 24 #include "nfcmrvl.h" 25 26 static unsigned int hci_muxed; 27 static unsigned int flow_control; 28 static unsigned int break_control; 29 static unsigned int reset_n_io; 30 31 /* 32 ** NFCMRVL NCI OPS 33 */ 34 35 static int nfcmrvl_uart_nci_open(struct nfcmrvl_private *priv) 36 { 37 return 0; 38 } 39 40 static int nfcmrvl_uart_nci_close(struct nfcmrvl_private *priv) 41 { 42 return 0; 43 } 44 45 static int nfcmrvl_uart_nci_send(struct nfcmrvl_private *priv, 46 struct sk_buff *skb) 47 { 48 struct nci_uart *nu = priv->drv_data; 49 50 return nu->ops.send(nu, skb); 51 } 52 53 static struct nfcmrvl_if_ops uart_ops = { 54 .nci_open = nfcmrvl_uart_nci_open, 55 .nci_close = nfcmrvl_uart_nci_close, 56 .nci_send = nfcmrvl_uart_nci_send, 57 }; 58 59 #ifdef CONFIG_OF 60 61 static int nfcmrvl_uart_parse_dt(struct device_node *node, 62 struct nfcmrvl_platform_data *pdata) 63 { 64 struct device_node *matched_node; 65 int ret; 66 67 matched_node = of_find_compatible_node(node, NULL, "mrvl,nfc-uart"); 68 if (!matched_node) 69 return -ENODEV; 70 71 ret = nfcmrvl_parse_dt(matched_node, pdata); 72 if (ret < 0) { 73 pr_err("Failed to get generic entries\n"); 74 return ret; 75 } 76 77 if (of_find_property(matched_node, "flow-control", NULL)) 78 pdata->flow_control = 1; 79 else 80 pdata->flow_control = 0; 81 82 if (of_find_property(matched_node, "break-control", NULL)) 83 pdata->break_control = 1; 84 else 85 pdata->break_control = 0; 86 87 return 0; 88 } 89 90 #else 91 92 static int nfcmrvl_uart_parse_dt(struct device_node *node, 93 struct nfcmrvl_platform_data *pdata) 94 { 95 return -ENODEV; 96 } 97 98 #endif 99 100 /* 101 ** NCI UART OPS 102 */ 103 104 static int nfcmrvl_nci_uart_open(struct nci_uart *nu) 105 { 106 struct nfcmrvl_private *priv; 107 struct nfcmrvl_platform_data *pdata = NULL; 108 struct nfcmrvl_platform_data config; 109 110 /* 111 * Platform data cannot be used here since usually it is already used 112 * by low level serial driver. We can try to retrieve serial device 113 * and check if DT entries were added. 114 */ 115 116 if (nu->tty->dev->parent && nu->tty->dev->parent->of_node) 117 if (nfcmrvl_uart_parse_dt(nu->tty->dev->parent->of_node, 118 &config) == 0) 119 pdata = &config; 120 121 if (!pdata) { 122 pr_info("No platform data / DT -> fallback to module params\n"); 123 config.hci_muxed = hci_muxed; 124 config.reset_n_io = reset_n_io; 125 config.flow_control = flow_control; 126 config.break_control = break_control; 127 pdata = &config; 128 } 129 130 priv = nfcmrvl_nci_register_dev(nu, &uart_ops, nu->tty->dev, pdata); 131 if (IS_ERR(priv)) 132 return PTR_ERR(priv); 133 134 priv->phy = NFCMRVL_PHY_UART; 135 136 nu->drv_data = priv; 137 nu->ndev = priv->ndev; 138 139 /* Set BREAK */ 140 if (priv->config.break_control && nu->tty->ops->break_ctl) 141 nu->tty->ops->break_ctl(nu->tty, -1); 142 143 return 0; 144 } 145 146 static void nfcmrvl_nci_uart_close(struct nci_uart *nu) 147 { 148 nfcmrvl_nci_unregister_dev((struct nfcmrvl_private *)nu->drv_data); 149 } 150 151 static int nfcmrvl_nci_uart_recv(struct nci_uart *nu, struct sk_buff *skb) 152 { 153 return nfcmrvl_nci_recv_frame((struct nfcmrvl_private *)nu->drv_data, 154 skb); 155 } 156 157 static void nfcmrvl_nci_uart_tx_start(struct nci_uart *nu) 158 { 159 struct nfcmrvl_private *priv = (struct nfcmrvl_private *)nu->drv_data; 160 161 /* Remove BREAK to wake up the NFCC */ 162 if (priv->config.break_control && nu->tty->ops->break_ctl) { 163 nu->tty->ops->break_ctl(nu->tty, 0); 164 usleep_range(3000, 5000); 165 } 166 } 167 168 static void nfcmrvl_nci_uart_tx_done(struct nci_uart *nu) 169 { 170 struct nfcmrvl_private *priv = (struct nfcmrvl_private *)nu->drv_data; 171 172 /* 173 ** To ensure that if the NFCC goes in DEEP SLEEP sate we can wake him 174 ** up. we set BREAK. Once we will be ready to send again we will remove 175 ** it. 176 */ 177 if (priv->config.break_control && nu->tty->ops->break_ctl) 178 nu->tty->ops->break_ctl(nu->tty, -1); 179 } 180 181 static struct nci_uart nfcmrvl_nci_uart = { 182 .owner = THIS_MODULE, 183 .name = "nfcmrvl_uart", 184 .driver = NCI_UART_DRIVER_MARVELL, 185 .ops = { 186 .open = nfcmrvl_nci_uart_open, 187 .close = nfcmrvl_nci_uart_close, 188 .recv = nfcmrvl_nci_uart_recv, 189 .tx_start = nfcmrvl_nci_uart_tx_start, 190 .tx_done = nfcmrvl_nci_uart_tx_done, 191 } 192 }; 193 194 /* 195 ** Module init 196 */ 197 198 static int nfcmrvl_uart_init_module(void) 199 { 200 return nci_uart_register(&nfcmrvl_nci_uart); 201 } 202 203 static void nfcmrvl_uart_exit_module(void) 204 { 205 nci_uart_unregister(&nfcmrvl_nci_uart); 206 } 207 208 module_init(nfcmrvl_uart_init_module); 209 module_exit(nfcmrvl_uart_exit_module); 210 211 MODULE_AUTHOR("Marvell International Ltd."); 212 MODULE_DESCRIPTION("Marvell NFC-over-UART"); 213 MODULE_LICENSE("GPL v2"); 214 215 module_param(flow_control, uint, 0); 216 MODULE_PARM_DESC(flow_control, "Tell if UART needs flow control at init."); 217 218 module_param(break_control, uint, 0); 219 MODULE_PARM_DESC(break_control, "Tell if UART driver must drive break signal."); 220 221 module_param(hci_muxed, uint, 0); 222 MODULE_PARM_DESC(hci_muxed, "Tell if transport is muxed in HCI one."); 223 224 module_param(reset_n_io, uint, 0); 225 MODULE_PARM_DESC(reset_n_io, "GPIO that is wired to RESET_N signal."); 226