Changes in 4.9.142 usb: core: Fix hub port connection events lost usb: dwc3: core: Clean up ULPI device usb: xhci: fix timeout for transition from RExit to U0 MAINTAINERS: Add Sasha as a stable branch maintainer gpio: don't free unallocated ida on gpiochip_add_data_with_key() error path iwlwifi: mvm: support sta_statistics() even on older firmware iwlwifi: mvm: fix regulatory domain update when the firmware starts brcmfmac: fix reporting support for 160 MHz channels tools/power/cpupower: fix compilation with STATIC=true v9fs_dir_readdir: fix double-free on p9stat_read error selinux: Add __GFP_NOWARN to allocation at str_read() bfs: add sanity check at bfs_fill_super() sctp: clear the transport of some out_chunk_list chunks in sctp_assoc_rm_peer gfs2: Don't leave s_fs_info pointing to freed memory in init_sbd llc: do not use sk_eat_skb() mm: don't warn about large allocations for slab drm/ast: change resolution may cause screen blurred drm/ast: fixed cursor may disappear sometimes drm/ast: Remove existing framebuffers before loading driver can: dev: can_get_echo_skb(): factor out non sending code to __can_get_echo_skb() can: dev: __can_get_echo_skb(): replace struct can_frame by canfd_frame to access frame length can: dev: __can_get_echo_skb(): Don't crash the kernel if can_priv::echo_skb is accessed out of bounds can: dev: __can_get_echo_skb(): print error message, if trying to echo non existing skb IB/core: Fix for core panic IB/hfi1: Eliminate races in the SDMA send error path usb: xhci: Prevent bus suspend if a port connect change or polling state is detected pinctrl: meson: fix pinconf bias disable KVM: PPC: Move and undef TRACE_INCLUDE_PATH/FILE cpufreq: imx6q: add return value check for voltage scale rtc: pcf2127: fix a kmemleak caused in pcf2127_i2c_gather_write floppy: fix race condition in __floppy_read_block_0() powerpc/io: Fix the IO workarounds code to work with Radix perf/x86/intel/uncore: Add more IMC PCI IDs for KabyLake and CoffeeLake CPUs SUNRPC: Fix a bogus get/put in generic_key_to_expire() kdb: Use strscpy with destination buffer size powerpc/numa: Suppress "VPHN is not supported" messages efi/arm: Revert deferred unmap of early memmap mapping tmpfs: make lseek(SEEK_DATA/SEK_HOLE) return ENXIO with a negative offset of: add helper to lookup compatible child node NFC: nfcmrvl_uart: fix OF child-node lookup net: bcmgenet: fix OF child-node lookup arm64: remove no-op -p linker flag ath10k: fix kernel panic due to race in accessing arvif list Input: xpad - add product ID for Xbox One S pad Input: xpad - fix Xbox One rumble stopping after 2.5 secs Input: xpad - correctly sort vendor id's Input: xpad - move reporting xbox one home button to common function Input: xpad - simplify error condition in init_output Input: xpad - don't depend on endpoint order Input: xpad - fix stuck mode button on Xbox One S pad Input: xpad - restore LED state after device resume Input: xpad - support some quirky Xbox One pads Input: xpad - sort supported devices by USB ID Input: xpad - sync supported devices with xboxdrv Input: xpad - add USB IDs for Mad Catz Brawlstick and Razer Sabertooth Input: xpad - sync supported devices with 360Controller Input: xpad - sync supported devices with XBCD Input: xpad - constify usb_device_id Input: xpad - fix PowerA init quirk for some gamepad models Input: xpad - validate USB endpoint type during probe Input: xpad - add support for PDP Xbox One controllers Input: xpad - add PDP device id 0x02a4 Input: xpad - fix some coding style issues Input: xpad - avoid using __set_bit() for capabilities Input: xpad - add GPD Win 2 Controller USB IDs Input: xpad - fix GPD Win 2 controller name Input: xpad - add support for Xbox1 PDP Camo series gamepad cw1200: Don't leak memory if krealloc failes mwifiex: prevent register accesses after host is sleeping mwifiex: report error to PCIe for suspend failure mwifiex: Fix NULL pointer dereference in skb_dequeue() mwifiex: fix p2p device doesn't find in scan problem scsi: ufs: fix bugs related to null pointer access and array size scsi: ufshcd: Fix race between clk scaling and ungate work scsi: ufs: fix race between clock gating and devfreq scaling work scsi: ufshcd: release resources if probe fails include/linux/pfn_t.h: force '~' to be parsed as an unary operator tty: wipe buffer. tty: wipe buffer if not echoing data usb: xhci: fix uninitialized completion when USB3 port got wrong status sched/core: Allow __sched_setscheduler() in interrupts when PI is not used namei: allow restricted O_CREAT of FIFOs and regular files lan78xx: Read MAC address from DT if present s390/mm: Check for valid vma before zapping in gmap_discard net: ieee802154: 6lowpan: fix frag reassembly Revert "evm: Translate user/group ids relative to s_user_ns when computing HMAC" ima: always measure and audit files in policy EVM: Add support for portable signature format ima: re-introduce own integrity cache lock ima: re-initialize iint->atomic_flags Linux 4.9.142 Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
233 lines
5.8 KiB
C
233 lines
5.8 KiB
C
/**
|
|
* Marvell NFC-over-UART driver
|
|
*
|
|
* Copyright (C) 2015, Marvell International Ltd.
|
|
*
|
|
* This software file (the "File") is distributed by Marvell International
|
|
* Ltd. under the terms of the GNU General Public License Version 2, June 1991
|
|
* (the "License"). You may use, redistribute and/or modify this File in
|
|
* accordance with the terms and conditions of the License, a copy of which
|
|
* is available on the worldwide web at
|
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
|
|
*
|
|
* THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE EXPRESSLY DISCLAIMED. The License provides additional details about
|
|
* this warranty disclaimer.
|
|
*/
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/of_gpio.h>
|
|
#include <net/nfc/nci.h>
|
|
#include <net/nfc/nci_core.h>
|
|
#include "nfcmrvl.h"
|
|
|
|
static unsigned int hci_muxed;
|
|
static unsigned int flow_control;
|
|
static unsigned int break_control;
|
|
static unsigned int reset_n_io;
|
|
|
|
/*
|
|
** NFCMRVL NCI OPS
|
|
*/
|
|
|
|
static int nfcmrvl_uart_nci_open(struct nfcmrvl_private *priv)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static int nfcmrvl_uart_nci_close(struct nfcmrvl_private *priv)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static int nfcmrvl_uart_nci_send(struct nfcmrvl_private *priv,
|
|
struct sk_buff *skb)
|
|
{
|
|
struct nci_uart *nu = priv->drv_data;
|
|
|
|
return nu->ops.send(nu, skb);
|
|
}
|
|
|
|
static void nfcmrvl_uart_nci_update_config(struct nfcmrvl_private *priv,
|
|
const void *param)
|
|
{
|
|
struct nci_uart *nu = priv->drv_data;
|
|
const struct nfcmrvl_fw_uart_config *config = param;
|
|
|
|
nci_uart_set_config(nu, le32_to_cpu(config->baudrate),
|
|
config->flow_control);
|
|
}
|
|
|
|
static struct nfcmrvl_if_ops uart_ops = {
|
|
.nci_open = nfcmrvl_uart_nci_open,
|
|
.nci_close = nfcmrvl_uart_nci_close,
|
|
.nci_send = nfcmrvl_uart_nci_send,
|
|
.nci_update_config = nfcmrvl_uart_nci_update_config
|
|
};
|
|
|
|
static int nfcmrvl_uart_parse_dt(struct device_node *node,
|
|
struct nfcmrvl_platform_data *pdata)
|
|
{
|
|
struct device_node *matched_node;
|
|
int ret;
|
|
|
|
matched_node = of_get_compatible_child(node, "marvell,nfc-uart");
|
|
if (!matched_node) {
|
|
matched_node = of_get_compatible_child(node, "mrvl,nfc-uart");
|
|
if (!matched_node)
|
|
return -ENODEV;
|
|
}
|
|
|
|
ret = nfcmrvl_parse_dt(matched_node, pdata);
|
|
if (ret < 0) {
|
|
pr_err("Failed to get generic entries\n");
|
|
return ret;
|
|
}
|
|
|
|
if (of_find_property(matched_node, "flow-control", NULL))
|
|
pdata->flow_control = 1;
|
|
else
|
|
pdata->flow_control = 0;
|
|
|
|
if (of_find_property(matched_node, "break-control", NULL))
|
|
pdata->break_control = 1;
|
|
else
|
|
pdata->break_control = 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
** NCI UART OPS
|
|
*/
|
|
|
|
static int nfcmrvl_nci_uart_open(struct nci_uart *nu)
|
|
{
|
|
struct nfcmrvl_private *priv;
|
|
struct nfcmrvl_platform_data *pdata = NULL;
|
|
struct nfcmrvl_platform_data config;
|
|
struct device *dev = nu->tty->dev;
|
|
|
|
/*
|
|
* Platform data cannot be used here since usually it is already used
|
|
* by low level serial driver. We can try to retrieve serial device
|
|
* and check if DT entries were added.
|
|
*/
|
|
|
|
if (dev && dev->parent && dev->parent->of_node)
|
|
if (nfcmrvl_uart_parse_dt(dev->parent->of_node, &config) == 0)
|
|
pdata = &config;
|
|
|
|
if (!pdata) {
|
|
pr_info("No platform data / DT -> fallback to module params\n");
|
|
config.hci_muxed = hci_muxed;
|
|
config.reset_n_io = reset_n_io;
|
|
config.flow_control = flow_control;
|
|
config.break_control = break_control;
|
|
pdata = &config;
|
|
}
|
|
|
|
priv = nfcmrvl_nci_register_dev(NFCMRVL_PHY_UART, nu, &uart_ops,
|
|
dev, pdata);
|
|
if (IS_ERR(priv))
|
|
return PTR_ERR(priv);
|
|
|
|
priv->support_fw_dnld = true;
|
|
|
|
nu->drv_data = priv;
|
|
nu->ndev = priv->ndev;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void nfcmrvl_nci_uart_close(struct nci_uart *nu)
|
|
{
|
|
nfcmrvl_nci_unregister_dev((struct nfcmrvl_private *)nu->drv_data);
|
|
}
|
|
|
|
static int nfcmrvl_nci_uart_recv(struct nci_uart *nu, struct sk_buff *skb)
|
|
{
|
|
return nfcmrvl_nci_recv_frame((struct nfcmrvl_private *)nu->drv_data,
|
|
skb);
|
|
}
|
|
|
|
static void nfcmrvl_nci_uart_tx_start(struct nci_uart *nu)
|
|
{
|
|
struct nfcmrvl_private *priv = (struct nfcmrvl_private *)nu->drv_data;
|
|
|
|
if (priv->ndev->nfc_dev->fw_download_in_progress)
|
|
return;
|
|
|
|
/* Remove BREAK to wake up the NFCC */
|
|
if (priv->config.break_control && nu->tty->ops->break_ctl) {
|
|
nu->tty->ops->break_ctl(nu->tty, 0);
|
|
usleep_range(3000, 5000);
|
|
}
|
|
}
|
|
|
|
static void nfcmrvl_nci_uart_tx_done(struct nci_uart *nu)
|
|
{
|
|
struct nfcmrvl_private *priv = (struct nfcmrvl_private *)nu->drv_data;
|
|
|
|
if (priv->ndev->nfc_dev->fw_download_in_progress)
|
|
return;
|
|
|
|
/*
|
|
** To ensure that if the NFCC goes in DEEP SLEEP sate we can wake him
|
|
** up. we set BREAK. Once we will be ready to send again we will remove
|
|
** it.
|
|
*/
|
|
if (priv->config.break_control && nu->tty->ops->break_ctl) {
|
|
nu->tty->ops->break_ctl(nu->tty, -1);
|
|
usleep_range(1000, 3000);
|
|
}
|
|
}
|
|
|
|
static struct nci_uart nfcmrvl_nci_uart = {
|
|
.owner = THIS_MODULE,
|
|
.name = "nfcmrvl_uart",
|
|
.driver = NCI_UART_DRIVER_MARVELL,
|
|
.ops = {
|
|
.open = nfcmrvl_nci_uart_open,
|
|
.close = nfcmrvl_nci_uart_close,
|
|
.recv = nfcmrvl_nci_uart_recv,
|
|
.tx_start = nfcmrvl_nci_uart_tx_start,
|
|
.tx_done = nfcmrvl_nci_uart_tx_done,
|
|
}
|
|
};
|
|
|
|
/*
|
|
** Module init
|
|
*/
|
|
|
|
static int nfcmrvl_uart_init_module(void)
|
|
{
|
|
return nci_uart_register(&nfcmrvl_nci_uart);
|
|
}
|
|
|
|
static void nfcmrvl_uart_exit_module(void)
|
|
{
|
|
nci_uart_unregister(&nfcmrvl_nci_uart);
|
|
}
|
|
|
|
module_init(nfcmrvl_uart_init_module);
|
|
module_exit(nfcmrvl_uart_exit_module);
|
|
|
|
MODULE_AUTHOR("Marvell International Ltd.");
|
|
MODULE_DESCRIPTION("Marvell NFC-over-UART");
|
|
MODULE_LICENSE("GPL v2");
|
|
|
|
module_param(flow_control, uint, 0);
|
|
MODULE_PARM_DESC(flow_control, "Tell if UART needs flow control at init.");
|
|
|
|
module_param(break_control, uint, 0);
|
|
MODULE_PARM_DESC(break_control, "Tell if UART driver must drive break signal.");
|
|
|
|
module_param(hci_muxed, uint, 0);
|
|
MODULE_PARM_DESC(hci_muxed, "Tell if transport is muxed in HCI one.");
|
|
|
|
module_param(reset_n_io, uint, 0);
|
|
MODULE_PARM_DESC(reset_n_io, "GPIO that is wired to RESET_N signal.");
|