162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Marvell NFC-over-UART driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2015, Marvell International Ltd.
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/module.h>
962306a36Sopenharmony_ci#include <linux/delay.h>
1062306a36Sopenharmony_ci#include <linux/of_gpio.h>
1162306a36Sopenharmony_ci#include <net/nfc/nci.h>
1262306a36Sopenharmony_ci#include <net/nfc/nci_core.h>
1362306a36Sopenharmony_ci#include "nfcmrvl.h"
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_cistatic unsigned int hci_muxed;
1662306a36Sopenharmony_cistatic unsigned int flow_control;
1762306a36Sopenharmony_cistatic unsigned int break_control;
1862306a36Sopenharmony_cistatic int reset_n_io = -EINVAL;
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci/*
2162306a36Sopenharmony_ci * NFCMRVL NCI OPS
2262306a36Sopenharmony_ci */
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_cistatic int nfcmrvl_uart_nci_open(struct nfcmrvl_private *priv)
2562306a36Sopenharmony_ci{
2662306a36Sopenharmony_ci	return 0;
2762306a36Sopenharmony_ci}
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_cistatic int nfcmrvl_uart_nci_close(struct nfcmrvl_private *priv)
3062306a36Sopenharmony_ci{
3162306a36Sopenharmony_ci	return 0;
3262306a36Sopenharmony_ci}
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_cistatic int nfcmrvl_uart_nci_send(struct nfcmrvl_private *priv,
3562306a36Sopenharmony_ci				 struct sk_buff *skb)
3662306a36Sopenharmony_ci{
3762306a36Sopenharmony_ci	struct nci_uart *nu = priv->drv_data;
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci	return nu->ops.send(nu, skb);
4062306a36Sopenharmony_ci}
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_cistatic void nfcmrvl_uart_nci_update_config(struct nfcmrvl_private *priv,
4362306a36Sopenharmony_ci					   const void *param)
4462306a36Sopenharmony_ci{
4562306a36Sopenharmony_ci	struct nci_uart *nu = priv->drv_data;
4662306a36Sopenharmony_ci	const struct nfcmrvl_fw_uart_config *config = param;
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci	nci_uart_set_config(nu, le32_to_cpu(config->baudrate),
4962306a36Sopenharmony_ci			    config->flow_control);
5062306a36Sopenharmony_ci}
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_cistatic const struct nfcmrvl_if_ops uart_ops = {
5362306a36Sopenharmony_ci	.nci_open = nfcmrvl_uart_nci_open,
5462306a36Sopenharmony_ci	.nci_close = nfcmrvl_uart_nci_close,
5562306a36Sopenharmony_ci	.nci_send = nfcmrvl_uart_nci_send,
5662306a36Sopenharmony_ci	.nci_update_config = nfcmrvl_uart_nci_update_config
5762306a36Sopenharmony_ci};
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_cistatic int nfcmrvl_uart_parse_dt(struct device_node *node,
6062306a36Sopenharmony_ci				 struct nfcmrvl_platform_data *pdata)
6162306a36Sopenharmony_ci{
6262306a36Sopenharmony_ci	struct device_node *matched_node;
6362306a36Sopenharmony_ci	int ret;
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	matched_node = of_get_compatible_child(node, "marvell,nfc-uart");
6662306a36Sopenharmony_ci	if (!matched_node) {
6762306a36Sopenharmony_ci		matched_node = of_get_compatible_child(node, "mrvl,nfc-uart");
6862306a36Sopenharmony_ci		if (!matched_node)
6962306a36Sopenharmony_ci			return -ENODEV;
7062306a36Sopenharmony_ci	}
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	ret = nfcmrvl_parse_dt(matched_node, pdata);
7362306a36Sopenharmony_ci	if (ret < 0) {
7462306a36Sopenharmony_ci		pr_err("Failed to get generic entries\n");
7562306a36Sopenharmony_ci		of_node_put(matched_node);
7662306a36Sopenharmony_ci		return ret;
7762306a36Sopenharmony_ci	}
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	pdata->flow_control = of_property_read_bool(matched_node, "flow-control");
8062306a36Sopenharmony_ci	pdata->break_control = of_property_read_bool(matched_node, "break-control");
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	of_node_put(matched_node);
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	return 0;
8562306a36Sopenharmony_ci}
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci/*
8862306a36Sopenharmony_ci * NCI UART OPS
8962306a36Sopenharmony_ci */
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_cistatic int nfcmrvl_nci_uart_open(struct nci_uart *nu)
9262306a36Sopenharmony_ci{
9362306a36Sopenharmony_ci	struct nfcmrvl_private *priv;
9462306a36Sopenharmony_ci	struct nfcmrvl_platform_data config;
9562306a36Sopenharmony_ci	const struct nfcmrvl_platform_data *pdata = NULL;
9662306a36Sopenharmony_ci	struct device *dev = nu->tty->dev;
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	/*
9962306a36Sopenharmony_ci	 * Platform data cannot be used here since usually it is already used
10062306a36Sopenharmony_ci	 * by low level serial driver. We can try to retrieve serial device
10162306a36Sopenharmony_ci	 * and check if DT entries were added.
10262306a36Sopenharmony_ci	 */
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	if (dev && dev->parent && dev->parent->of_node)
10562306a36Sopenharmony_ci		if (nfcmrvl_uart_parse_dt(dev->parent->of_node, &config) == 0)
10662306a36Sopenharmony_ci			pdata = &config;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	if (!pdata) {
10962306a36Sopenharmony_ci		pr_info("No platform data / DT -> fallback to module params\n");
11062306a36Sopenharmony_ci		config.hci_muxed = hci_muxed;
11162306a36Sopenharmony_ci		config.reset_n_io = reset_n_io;
11262306a36Sopenharmony_ci		config.flow_control = flow_control;
11362306a36Sopenharmony_ci		config.break_control = break_control;
11462306a36Sopenharmony_ci		pdata = &config;
11562306a36Sopenharmony_ci	}
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	priv = nfcmrvl_nci_register_dev(NFCMRVL_PHY_UART, nu, &uart_ops,
11862306a36Sopenharmony_ci					dev, pdata);
11962306a36Sopenharmony_ci	if (IS_ERR(priv))
12062306a36Sopenharmony_ci		return PTR_ERR(priv);
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	priv->support_fw_dnld = true;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	nu->drv_data = priv;
12562306a36Sopenharmony_ci	nu->ndev = priv->ndev;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	return 0;
12862306a36Sopenharmony_ci}
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_cistatic void nfcmrvl_nci_uart_close(struct nci_uart *nu)
13162306a36Sopenharmony_ci{
13262306a36Sopenharmony_ci	nfcmrvl_nci_unregister_dev((struct nfcmrvl_private *)nu->drv_data);
13362306a36Sopenharmony_ci}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_cistatic int nfcmrvl_nci_uart_recv(struct nci_uart *nu, struct sk_buff *skb)
13662306a36Sopenharmony_ci{
13762306a36Sopenharmony_ci	return nfcmrvl_nci_recv_frame((struct nfcmrvl_private *)nu->drv_data,
13862306a36Sopenharmony_ci				      skb);
13962306a36Sopenharmony_ci}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_cistatic void nfcmrvl_nci_uart_tx_start(struct nci_uart *nu)
14262306a36Sopenharmony_ci{
14362306a36Sopenharmony_ci	struct nfcmrvl_private *priv = (struct nfcmrvl_private *)nu->drv_data;
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	if (priv->ndev->nfc_dev->fw_download_in_progress)
14662306a36Sopenharmony_ci		return;
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	/* Remove BREAK to wake up the NFCC */
14962306a36Sopenharmony_ci	if (priv->config.break_control && nu->tty->ops->break_ctl) {
15062306a36Sopenharmony_ci		nu->tty->ops->break_ctl(nu->tty, 0);
15162306a36Sopenharmony_ci		usleep_range(3000, 5000);
15262306a36Sopenharmony_ci	}
15362306a36Sopenharmony_ci}
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_cistatic void nfcmrvl_nci_uart_tx_done(struct nci_uart *nu)
15662306a36Sopenharmony_ci{
15762306a36Sopenharmony_ci	struct nfcmrvl_private *priv = (struct nfcmrvl_private *)nu->drv_data;
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	if (priv->ndev->nfc_dev->fw_download_in_progress)
16062306a36Sopenharmony_ci		return;
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	/*
16362306a36Sopenharmony_ci	 * To ensure that if the NFCC goes in DEEP SLEEP sate we can wake him
16462306a36Sopenharmony_ci	 * up. we set BREAK. Once we will be ready to send again we will remove
16562306a36Sopenharmony_ci	 * it.
16662306a36Sopenharmony_ci	 */
16762306a36Sopenharmony_ci	if (priv->config.break_control && nu->tty->ops->break_ctl) {
16862306a36Sopenharmony_ci		nu->tty->ops->break_ctl(nu->tty, -1);
16962306a36Sopenharmony_ci		usleep_range(1000, 3000);
17062306a36Sopenharmony_ci	}
17162306a36Sopenharmony_ci}
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_cistatic struct nci_uart nfcmrvl_nci_uart = {
17462306a36Sopenharmony_ci	.owner  = THIS_MODULE,
17562306a36Sopenharmony_ci	.name   = "nfcmrvl_uart",
17662306a36Sopenharmony_ci	.driver = NCI_UART_DRIVER_MARVELL,
17762306a36Sopenharmony_ci	.ops	= {
17862306a36Sopenharmony_ci		.open		= nfcmrvl_nci_uart_open,
17962306a36Sopenharmony_ci		.close		= nfcmrvl_nci_uart_close,
18062306a36Sopenharmony_ci		.recv		= nfcmrvl_nci_uart_recv,
18162306a36Sopenharmony_ci		.tx_start	= nfcmrvl_nci_uart_tx_start,
18262306a36Sopenharmony_ci		.tx_done	= nfcmrvl_nci_uart_tx_done,
18362306a36Sopenharmony_ci	}
18462306a36Sopenharmony_ci};
18562306a36Sopenharmony_cimodule_driver(nfcmrvl_nci_uart, nci_uart_register, nci_uart_unregister);
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ciMODULE_AUTHOR("Marvell International Ltd.");
18862306a36Sopenharmony_ciMODULE_DESCRIPTION("Marvell NFC-over-UART");
18962306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_cimodule_param(flow_control, uint, 0);
19262306a36Sopenharmony_ciMODULE_PARM_DESC(flow_control, "Tell if UART needs flow control at init.");
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_cimodule_param(break_control, uint, 0);
19562306a36Sopenharmony_ciMODULE_PARM_DESC(break_control, "Tell if UART driver must drive break signal.");
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_cimodule_param(hci_muxed, uint, 0);
19862306a36Sopenharmony_ciMODULE_PARM_DESC(hci_muxed, "Tell if transport is muxed in HCI one.");
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_cimodule_param(reset_n_io, int, 0);
20162306a36Sopenharmony_ciMODULE_PARM_DESC(reset_n_io, "GPIO that is wired to RESET_N signal.");
202