1 // SPDX-License-Identifier: GPL-2.0-only
3 * Marvell NFC-over-UART driver
5 * Copyright (C) 2015, Marvell International Ltd.
8 #include <linux/module.h>
9 #include <linux/delay.h>
10 #include <linux/of_gpio.h>
11 #include <net/nfc/nci.h>
12 #include <net/nfc/nci_core.h>
15 static unsigned int hci_muxed
;
16 static unsigned int flow_control
;
17 static unsigned int break_control
;
18 static int reset_n_io
= -EINVAL
;
24 static int nfcmrvl_uart_nci_open(struct nfcmrvl_private
*priv
)
29 static int nfcmrvl_uart_nci_close(struct nfcmrvl_private
*priv
)
34 static int nfcmrvl_uart_nci_send(struct nfcmrvl_private
*priv
,
37 struct nci_uart
*nu
= priv
->drv_data
;
39 return nu
->ops
.send(nu
, skb
);
42 static void nfcmrvl_uart_nci_update_config(struct nfcmrvl_private
*priv
,
45 struct nci_uart
*nu
= priv
->drv_data
;
46 const struct nfcmrvl_fw_uart_config
*config
= param
;
48 nci_uart_set_config(nu
, le32_to_cpu(config
->baudrate
),
49 config
->flow_control
);
52 static const struct nfcmrvl_if_ops uart_ops
= {
53 .nci_open
= nfcmrvl_uart_nci_open
,
54 .nci_close
= nfcmrvl_uart_nci_close
,
55 .nci_send
= nfcmrvl_uart_nci_send
,
56 .nci_update_config
= nfcmrvl_uart_nci_update_config
59 static int nfcmrvl_uart_parse_dt(struct device_node
*node
,
60 struct nfcmrvl_platform_data
*pdata
)
62 struct device_node
*matched_node
;
65 matched_node
= of_get_compatible_child(node
, "marvell,nfc-uart");
67 matched_node
= of_get_compatible_child(node
, "mrvl,nfc-uart");
72 ret
= nfcmrvl_parse_dt(matched_node
, pdata
);
74 pr_err("Failed to get generic entries\n");
75 of_node_put(matched_node
);
79 pdata
->flow_control
= of_property_read_bool(matched_node
, "flow-control");
80 pdata
->break_control
= of_property_read_bool(matched_node
, "break-control");
82 of_node_put(matched_node
);
91 static int nfcmrvl_nci_uart_open(struct nci_uart
*nu
)
93 struct nfcmrvl_private
*priv
;
94 struct nfcmrvl_platform_data config
;
95 const struct nfcmrvl_platform_data
*pdata
= NULL
;
96 struct device
*dev
= nu
->tty
->dev
;
99 * Platform data cannot be used here since usually it is already used
100 * by low level serial driver. We can try to retrieve serial device
101 * and check if DT entries were added.
104 if (dev
&& dev
->parent
&& dev
->parent
->of_node
)
105 if (nfcmrvl_uart_parse_dt(dev
->parent
->of_node
, &config
) == 0)
109 pr_info("No platform data / DT -> fallback to module params\n");
110 config
.hci_muxed
= hci_muxed
;
111 config
.reset_n_io
= reset_n_io
;
112 config
.flow_control
= flow_control
;
113 config
.break_control
= break_control
;
117 priv
= nfcmrvl_nci_register_dev(NFCMRVL_PHY_UART
, nu
, &uart_ops
,
120 return PTR_ERR(priv
);
122 priv
->support_fw_dnld
= true;
125 nu
->ndev
= priv
->ndev
;
130 static void nfcmrvl_nci_uart_close(struct nci_uart
*nu
)
132 nfcmrvl_nci_unregister_dev((struct nfcmrvl_private
*)nu
->drv_data
);
135 static int nfcmrvl_nci_uart_recv(struct nci_uart
*nu
, struct sk_buff
*skb
)
137 return nfcmrvl_nci_recv_frame((struct nfcmrvl_private
*)nu
->drv_data
,
141 static void nfcmrvl_nci_uart_tx_start(struct nci_uart
*nu
)
143 struct nfcmrvl_private
*priv
= (struct nfcmrvl_private
*)nu
->drv_data
;
145 if (priv
->ndev
->nfc_dev
->fw_download_in_progress
)
148 /* Remove BREAK to wake up the NFCC */
149 if (priv
->config
.break_control
&& nu
->tty
->ops
->break_ctl
) {
150 nu
->tty
->ops
->break_ctl(nu
->tty
, 0);
151 usleep_range(3000, 5000);
155 static void nfcmrvl_nci_uart_tx_done(struct nci_uart
*nu
)
157 struct nfcmrvl_private
*priv
= (struct nfcmrvl_private
*)nu
->drv_data
;
159 if (priv
->ndev
->nfc_dev
->fw_download_in_progress
)
163 * To ensure that if the NFCC goes in DEEP SLEEP sate we can wake him
164 * up. we set BREAK. Once we will be ready to send again we will remove
167 if (priv
->config
.break_control
&& nu
->tty
->ops
->break_ctl
) {
168 nu
->tty
->ops
->break_ctl(nu
->tty
, -1);
169 usleep_range(1000, 3000);
173 static struct nci_uart nfcmrvl_nci_uart
= {
174 .owner
= THIS_MODULE
,
175 .name
= "nfcmrvl_uart",
176 .driver
= NCI_UART_DRIVER_MARVELL
,
178 .open
= nfcmrvl_nci_uart_open
,
179 .close
= nfcmrvl_nci_uart_close
,
180 .recv
= nfcmrvl_nci_uart_recv
,
181 .tx_start
= nfcmrvl_nci_uart_tx_start
,
182 .tx_done
= nfcmrvl_nci_uart_tx_done
,
185 module_driver(nfcmrvl_nci_uart
, nci_uart_register
, nci_uart_unregister
);
187 MODULE_AUTHOR("Marvell International Ltd.");
188 MODULE_DESCRIPTION("Marvell NFC-over-UART");
189 MODULE_LICENSE("GPL v2");
191 module_param(flow_control
, uint
, 0);
192 MODULE_PARM_DESC(flow_control
, "Tell if UART needs flow control at init.");
194 module_param(break_control
, uint
, 0);
195 MODULE_PARM_DESC(break_control
, "Tell if UART driver must drive break signal.");
197 module_param(hci_muxed
, uint
, 0);
198 MODULE_PARM_DESC(hci_muxed
, "Tell if transport is muxed in HCI one.");
200 module_param(reset_n_io
, int, 0);
201 MODULE_PARM_DESC(reset_n_io
, "GPIO that is wired to RESET_N signal.");