FILE
uart.c
File preview with syntax highlighting.
linux-6.19.14/drivers/nfc/nfcmrvl/uart.c
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Marvell NFC-over-UART driver 4 * 5 * Copyright (C) 2015, Marvell International Ltd. 6 */ 7 8#include <linux/delay.h> 9#include <linux/device.h> 10#include <linux/err.h> 11#include <linux/module.h> 12#include <linux/of.h> 13#include <linux/printk.h> 14 15#include <net/nfc/nci.h> 16#include <net/nfc/nci_core.h> 17 18#include "nfcmrvl.h" 19 20static unsigned int hci_muxed; 21static unsigned int flow_control; 22static unsigned int break_control; 23static int reset_n_io = -EINVAL; 24 25/* 26 * NFCMRVL NCI OPS 27 */ 28 29static int nfcmrvl_uart_nci_open(struct nfcmrvl_private *priv) 30{ 31 return 0; 32} 33 34static int nfcmrvl_uart_nci_close(struct nfcmrvl_private *priv) 35{ 36 return 0; 37} 38 39static int nfcmrvl_uart_nci_send(struct nfcmrvl_private *priv, 40 struct sk_buff *skb) 41{ 42 struct nci_uart *nu = priv->drv_data; 43 44 return nu->ops.send(nu, skb); 45} 46 47static void nfcmrvl_uart_nci_update_config(struct nfcmrvl_private *priv, 48 const void *param) 49{ 50 struct nci_uart *nu = priv->drv_data; 51 const struct nfcmrvl_fw_uart_config *config = param; 52 53 nci_uart_set_config(nu, le32_to_cpu(config->baudrate), 54 config->flow_control); 55} 56 57static const struct nfcmrvl_if_ops uart_ops = { 58 .nci_open = nfcmrvl_uart_nci_open, 59 .nci_close = nfcmrvl_uart_nci_close, 60 .nci_send = nfcmrvl_uart_nci_send, 61 .nci_update_config = nfcmrvl_uart_nci_update_config 62}; 63 64static int nfcmrvl_uart_parse_dt(struct device_node *node, 65 struct nfcmrvl_platform_data *pdata) 66{ 67 struct device_node *matched_node; 68 int ret; 69 70 matched_node = of_get_compatible_child(node, "marvell,nfc-uart"); 71 if (!matched_node) { 72 matched_node = of_get_compatible_child(node, "mrvl,nfc-uart"); 73 if (!matched_node) 74 return -ENODEV; 75 } 76 77 ret = nfcmrvl_parse_dt(matched_node, pdata); 78 if (ret < 0) { 79 pr_err("Failed to get generic entries\n"); 80 of_node_put(matched_node); 81 return ret; 82 } 83 84 pdata->flow_control = of_property_read_bool(matched_node, "flow-control"); 85 pdata->break_control = of_property_read_bool(matched_node, "break-control"); 86 87 of_node_put(matched_node); 88 89 return 0; 90} 91 92/* 93 * NCI UART OPS 94 */ 95 96static int nfcmrvl_nci_uart_open(struct nci_uart *nu) 97{ 98 struct nfcmrvl_private *priv; 99 struct nfcmrvl_platform_data config; 100 const struct nfcmrvl_platform_data *pdata = NULL; 101 struct device *dev = nu->tty->dev; 102 103 /* 104 * Platform data cannot be used here since usually it is already used 105 * by low level serial driver. We can try to retrieve serial device 106 * and check if DT entries were added. 107 */ 108 109 if (dev && dev->parent && dev->parent->of_node) 110 if (nfcmrvl_uart_parse_dt(dev->parent->of_node, &config) == 0) 111 pdata = &config; 112 113 if (!pdata) { 114 pr_info("No platform data / DT -> fallback to module params\n"); 115 config.hci_muxed = hci_muxed; 116 config.reset_n_io = reset_n_io; 117 config.flow_control = flow_control; 118 config.break_control = break_control; 119 pdata = &config; 120 } 121 122 priv = nfcmrvl_nci_register_dev(NFCMRVL_PHY_UART, nu, &uart_ops, 123 dev, pdata); 124 if (IS_ERR(priv)) 125 return PTR_ERR(priv); 126 127 priv->support_fw_dnld = true; 128 129 nu->drv_data = priv; 130 nu->ndev = priv->ndev; 131 132 return 0; 133} 134 135static void nfcmrvl_nci_uart_close(struct nci_uart *nu) 136{ 137 nfcmrvl_nci_unregister_dev((struct nfcmrvl_private *)nu->drv_data); 138} 139 140static int nfcmrvl_nci_uart_recv(struct nci_uart *nu, struct sk_buff *skb) 141{ 142 return nfcmrvl_nci_recv_frame((struct nfcmrvl_private *)nu->drv_data, 143 skb); 144} 145 146static void nfcmrvl_nci_uart_tx_start(struct nci_uart *nu) 147{ 148 struct nfcmrvl_private *priv = (struct nfcmrvl_private *)nu->drv_data; 149 150 if (priv->ndev->nfc_dev->fw_download_in_progress) 151 return; 152 153 /* Remove BREAK to wake up the NFCC */ 154 if (priv->config.break_control && nu->tty->ops->break_ctl) { 155 nu->tty->ops->break_ctl(nu->tty, 0); 156 usleep_range(3000, 5000); 157 } 158} 159 160static void nfcmrvl_nci_uart_tx_done(struct nci_uart *nu) 161{ 162 struct nfcmrvl_private *priv = (struct nfcmrvl_private *)nu->drv_data; 163 164 if (priv->ndev->nfc_dev->fw_download_in_progress) 165 return; 166 167 /* 168 * To ensure that if the NFCC goes in DEEP SLEEP sate we can wake him 169 * up. we set BREAK. Once we will be ready to send again we will remove 170 * it. 171 */ 172 if (priv->config.break_control && nu->tty->ops->break_ctl) { 173 nu->tty->ops->break_ctl(nu->tty, -1); 174 usleep_range(1000, 3000); 175 } 176} 177 178static struct nci_uart nfcmrvl_nci_uart = { 179 .owner = THIS_MODULE, 180 .name = "nfcmrvl_uart", 181 .driver = NCI_UART_DRIVER_MARVELL, 182 .ops = { 183 .open = nfcmrvl_nci_uart_open, 184 .close = nfcmrvl_nci_uart_close, 185 .recv = nfcmrvl_nci_uart_recv, 186 .tx_start = nfcmrvl_nci_uart_tx_start, 187 .tx_done = nfcmrvl_nci_uart_tx_done, 188 } 189}; 190module_driver(nfcmrvl_nci_uart, nci_uart_register, nci_uart_unregister); 191 192MODULE_AUTHOR("Marvell International Ltd."); 193MODULE_DESCRIPTION("Marvell NFC-over-UART"); 194MODULE_LICENSE("GPL v2"); 195 196module_param(flow_control, uint, 0); 197MODULE_PARM_DESC(flow_control, "Tell if UART needs flow control at init."); 198 199module_param(break_control, uint, 0); 200MODULE_PARM_DESC(break_control, "Tell if UART driver must drive break signal."); 201 202module_param(hci_muxed, uint, 0); 203MODULE_PARM_DESC(hci_muxed, "Tell if transport is muxed in HCI one."); 204 205module_param(reset_n_io, int, 0); 206MODULE_PARM_DESC(reset_n_io, "GPIO that is wired to RESET_N signal.");
~/
Read-only file preview.