-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
nfc: s3fwrn5: Add driver for Samsung S3FWRN5 NFC Chip
Add driver for Samsung S3FWRN5 NFC controller. S3FWRN5 is using NCI protocol and I2C communication interface. Signed-off-by: Robert Baldyga <r.baldyga@samsung.com> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
- Loading branch information
Robert Baldyga
authored and
Samuel Ortiz
committed
Aug 20, 2015
1 parent
025a0cb
commit c04c674
Showing
13 changed files
with
1,565 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
* Samsung S3FWRN5 NCI NFC Controller | ||
|
||
Required properties: | ||
- compatible: Should be "samsung,s3fwrn5-i2c". | ||
- reg: address on the bus | ||
- interrupt-parent: phandle for the interrupt gpio controller | ||
- interrupts: GPIO interrupt to which the chip is connected | ||
- s3fwrn5,en-gpios: Output GPIO pin used for enabling/disabling the chip | ||
- s3fwrn5,fw-gpios: Output GPIO pin used to enter firmware mode and | ||
sleep/wakeup control | ||
|
||
Example: | ||
|
||
&hsi2c_4 { | ||
status = "okay"; | ||
s3fwrn5@27 { | ||
compatible = "samsung,s3fwrn5-i2c"; | ||
|
||
reg = <0x27>; | ||
|
||
interrupt-parent = <&gpa1>; | ||
interrupts = <3 0 0>; | ||
|
||
s3fwrn5,en-gpios = <&gpf1 4 0>; | ||
s3fwrn5,fw-gpios = <&gpj0 2 0>; | ||
}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
config NFC_S3FWRN5 | ||
tristate | ||
---help--- | ||
Core driver for Samsung S3FWRN5 NFC chip. Contains core utilities | ||
of chip. It's intended to be used by PHYs to avoid duplicating lots | ||
of common code. | ||
|
||
config NFC_S3FWRN5_I2C | ||
tristate "Samsung S3FWRN5 I2C support" | ||
depends on NFC_NCI && I2C | ||
select NFC_S3FWRN5 | ||
default n | ||
---help--- | ||
This module adds support for an I2C interface to the S3FWRN5 chip. | ||
Select this if your platform is using the I2C bus. | ||
|
||
To compile this driver as a module, choose m here. The module will | ||
be called s3fwrn5_i2c.ko. | ||
Say N if unsure. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
# | ||
# Makefile for Samsung S3FWRN5 NFC driver | ||
# | ||
|
||
s3fwrn5-objs = core.o firmware.o nci.o | ||
s3fwrn5_i2c-objs = i2c.o | ||
|
||
obj-$(CONFIG_NFC_S3FWRN5) += s3fwrn5.o | ||
obj-$(CONFIG_NFC_S3FWRN5_I2C) += s3fwrn5_i2c.o | ||
|
||
ccflags-$(CONFIG_NFC_DEBUG) := -DDEBUG |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,219 @@ | ||
/* | ||
* NCI based driver for Samsung S3FWRN5 NFC chip | ||
* | ||
* Copyright (C) 2015 Samsung Electrnoics | ||
* Robert Baldyga <r.baldyga@samsung.com> | ||
* | ||
* This program is free software; you can redistribute it and/or modify it | ||
* under the terms and conditions of the GNU General Public License, | ||
* version 2 or later, as published by the Free Software Foundation. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* along with this program; if not, see <http://www.gnu.org/licenses/>. | ||
*/ | ||
|
||
#include <linux/module.h> | ||
#include <net/nfc/nci_core.h> | ||
|
||
#include "s3fwrn5.h" | ||
#include "firmware.h" | ||
#include "nci.h" | ||
|
||
#define S3FWRN5_NFC_PROTOCOLS (NFC_PROTO_JEWEL_MASK | \ | ||
NFC_PROTO_MIFARE_MASK | \ | ||
NFC_PROTO_FELICA_MASK | \ | ||
NFC_PROTO_ISO14443_MASK | \ | ||
NFC_PROTO_ISO14443_B_MASK | \ | ||
NFC_PROTO_ISO15693_MASK) | ||
|
||
static int s3fwrn5_firmware_update(struct s3fwrn5_info *info) | ||
{ | ||
bool need_update; | ||
int ret; | ||
|
||
s3fwrn5_fw_init(&info->fw_info, "sec_s3fwrn5_firmware.bin"); | ||
|
||
/* Update firmware */ | ||
|
||
s3fwrn5_set_wake(info, false); | ||
s3fwrn5_set_mode(info, S3FWRN5_MODE_FW); | ||
|
||
ret = s3fwrn5_fw_setup(&info->fw_info); | ||
if (ret < 0) | ||
return ret; | ||
|
||
need_update = s3fwrn5_fw_check_version(&info->fw_info, | ||
info->ndev->manufact_specific_info); | ||
if (!need_update) | ||
goto out; | ||
|
||
dev_info(&info->ndev->nfc_dev->dev, "Detected new firmware version\n"); | ||
|
||
ret = s3fwrn5_fw_download(&info->fw_info); | ||
if (ret < 0) | ||
goto out; | ||
|
||
/* Update RF configuration */ | ||
|
||
s3fwrn5_set_mode(info, S3FWRN5_MODE_NCI); | ||
|
||
s3fwrn5_set_wake(info, true); | ||
ret = s3fwrn5_nci_rf_configure(info, "sec_s3fwrn5_rfreg.bin"); | ||
s3fwrn5_set_wake(info, false); | ||
|
||
out: | ||
s3fwrn5_set_mode(info, S3FWRN5_MODE_COLD); | ||
s3fwrn5_fw_cleanup(&info->fw_info); | ||
return ret; | ||
} | ||
|
||
static int s3fwrn5_nci_open(struct nci_dev *ndev) | ||
{ | ||
struct s3fwrn5_info *info = nci_get_drvdata(ndev); | ||
|
||
if (s3fwrn5_get_mode(info) != S3FWRN5_MODE_COLD) | ||
return -EBUSY; | ||
|
||
s3fwrn5_set_mode(info, S3FWRN5_MODE_NCI); | ||
s3fwrn5_set_wake(info, true); | ||
|
||
return 0; | ||
} | ||
|
||
static int s3fwrn5_nci_close(struct nci_dev *ndev) | ||
{ | ||
struct s3fwrn5_info *info = nci_get_drvdata(ndev); | ||
|
||
s3fwrn5_set_wake(info, false); | ||
s3fwrn5_set_mode(info, S3FWRN5_MODE_COLD); | ||
|
||
return 0; | ||
} | ||
|
||
static int s3fwrn5_nci_send(struct nci_dev *ndev, struct sk_buff *skb) | ||
{ | ||
struct s3fwrn5_info *info = nci_get_drvdata(ndev); | ||
int ret; | ||
|
||
mutex_lock(&info->mutex); | ||
|
||
if (s3fwrn5_get_mode(info) != S3FWRN5_MODE_NCI) { | ||
mutex_unlock(&info->mutex); | ||
return -EINVAL; | ||
} | ||
|
||
ret = s3fwrn5_write(info, skb); | ||
if (ret < 0) | ||
kfree_skb(skb); | ||
|
||
mutex_unlock(&info->mutex); | ||
return ret; | ||
} | ||
|
||
static int s3fwrn5_nci_post_setup(struct nci_dev *ndev) | ||
{ | ||
struct s3fwrn5_info *info = nci_get_drvdata(ndev); | ||
int ret; | ||
|
||
ret = s3fwrn5_firmware_update(info); | ||
if (ret < 0) | ||
goto out; | ||
|
||
/* NCI core reset */ | ||
|
||
s3fwrn5_set_mode(info, S3FWRN5_MODE_NCI); | ||
s3fwrn5_set_wake(info, true); | ||
|
||
ret = nci_core_reset(info->ndev); | ||
if (ret < 0) | ||
goto out; | ||
|
||
ret = nci_core_init(info->ndev); | ||
|
||
out: | ||
return ret; | ||
} | ||
|
||
static struct nci_ops s3fwrn5_nci_ops = { | ||
.open = s3fwrn5_nci_open, | ||
.close = s3fwrn5_nci_close, | ||
.send = s3fwrn5_nci_send, | ||
.post_setup = s3fwrn5_nci_post_setup, | ||
}; | ||
|
||
int s3fwrn5_probe(struct nci_dev **ndev, void *phy_id, struct device *pdev, | ||
struct s3fwrn5_phy_ops *phy_ops, unsigned int max_payload) | ||
{ | ||
struct s3fwrn5_info *info; | ||
int ret; | ||
|
||
info = devm_kzalloc(pdev, sizeof(*info), GFP_KERNEL); | ||
if (!info) | ||
return -ENOMEM; | ||
|
||
info->phy_id = phy_id; | ||
info->pdev = pdev; | ||
info->phy_ops = phy_ops; | ||
info->max_payload = max_payload; | ||
mutex_init(&info->mutex); | ||
|
||
s3fwrn5_set_mode(info, S3FWRN5_MODE_COLD); | ||
|
||
s3fwrn5_nci_get_prop_ops(&s3fwrn5_nci_ops.prop_ops, | ||
&s3fwrn5_nci_ops.n_prop_ops); | ||
|
||
info->ndev = nci_allocate_device(&s3fwrn5_nci_ops, | ||
S3FWRN5_NFC_PROTOCOLS, 0, 0); | ||
if (!info->ndev) | ||
return -ENOMEM; | ||
|
||
nci_set_parent_dev(info->ndev, pdev); | ||
nci_set_drvdata(info->ndev, info); | ||
|
||
ret = nci_register_device(info->ndev); | ||
if (ret < 0) { | ||
nci_free_device(info->ndev); | ||
return ret; | ||
} | ||
|
||
info->fw_info.ndev = info->ndev; | ||
|
||
*ndev = info->ndev; | ||
|
||
return ret; | ||
} | ||
EXPORT_SYMBOL(s3fwrn5_probe); | ||
|
||
void s3fwrn5_remove(struct nci_dev *ndev) | ||
{ | ||
struct s3fwrn5_info *info = nci_get_drvdata(ndev); | ||
|
||
s3fwrn5_set_mode(info, S3FWRN5_MODE_COLD); | ||
|
||
nci_unregister_device(ndev); | ||
nci_free_device(ndev); | ||
} | ||
EXPORT_SYMBOL(s3fwrn5_remove); | ||
|
||
int s3fwrn5_recv_frame(struct nci_dev *ndev, struct sk_buff *skb, | ||
enum s3fwrn5_mode mode) | ||
{ | ||
switch (mode) { | ||
case S3FWRN5_MODE_NCI: | ||
return nci_recv_frame(ndev, skb); | ||
case S3FWRN5_MODE_FW: | ||
return s3fwrn5_fw_recv_frame(ndev, skb); | ||
default: | ||
return -ENODEV; | ||
} | ||
} | ||
EXPORT_SYMBOL(s3fwrn5_recv_frame); | ||
|
||
MODULE_LICENSE("GPL"); | ||
MODULE_DESCRIPTION("Samsung S3FWRN5 NFC driver"); | ||
MODULE_AUTHOR("Robert Baldyga <r.baldyga@samsung.com>"); |
Oops, something went wrong.