Commit b3799d59 authored by Bongsu Jeon's avatar Bongsu Jeon Committed by Jakub Kicinski

nfc: s3fwrn5: extract the common phy blocks

Extract the common phy blocks to reuse it.
The UART module will use the common blocks.
Reviewed-by: default avatarKrzysztof Kozlowski <krzk@kernel.org>
Signed-off-by: default avatarBongsu Jeon <bongsu.jeon@samsung.com>
Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 337da149
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
# Makefile for Samsung S3FWRN5 NFC driver # Makefile for Samsung S3FWRN5 NFC driver
# #
s3fwrn5-objs = core.o firmware.o nci.o s3fwrn5-objs = core.o firmware.o nci.o phy_common.o
s3fwrn5_i2c-objs = i2c.o s3fwrn5_i2c-objs = i2c.o
obj-$(CONFIG_NFC_S3FWRN5) += s3fwrn5.o obj-$(CONFIG_NFC_S3FWRN5) += s3fwrn5.o
......
...@@ -15,75 +15,30 @@ ...@@ -15,75 +15,30 @@
#include <net/nfc/nfc.h> #include <net/nfc/nfc.h>
#include "s3fwrn5.h" #include "phy_common.h"
#define S3FWRN5_I2C_DRIVER_NAME "s3fwrn5_i2c" #define S3FWRN5_I2C_DRIVER_NAME "s3fwrn5_i2c"
#define S3FWRN5_EN_WAIT_TIME 20
struct s3fwrn5_i2c_phy { struct s3fwrn5_i2c_phy {
struct phy_common common;
struct i2c_client *i2c_dev; struct i2c_client *i2c_dev;
struct nci_dev *ndev;
int gpio_en;
int gpio_fw_wake;
struct mutex mutex;
enum s3fwrn5_mode mode;
unsigned int irq_skip:1; unsigned int irq_skip:1;
}; };
static void s3fwrn5_i2c_set_wake(void *phy_id, bool wake)
{
struct s3fwrn5_i2c_phy *phy = phy_id;
mutex_lock(&phy->mutex);
gpio_set_value(phy->gpio_fw_wake, wake);
msleep(S3FWRN5_EN_WAIT_TIME);
mutex_unlock(&phy->mutex);
}
static void s3fwrn5_i2c_set_mode(void *phy_id, enum s3fwrn5_mode mode) static void s3fwrn5_i2c_set_mode(void *phy_id, enum s3fwrn5_mode mode)
{ {
struct s3fwrn5_i2c_phy *phy = phy_id; struct s3fwrn5_i2c_phy *phy = phy_id;
mutex_lock(&phy->mutex); mutex_lock(&phy->common.mutex);
if (phy->mode == mode) if (s3fwrn5_phy_power_ctrl(&phy->common, mode) == false)
goto out; goto out;
phy->mode = mode;
gpio_set_value(phy->gpio_en, 1);
gpio_set_value(phy->gpio_fw_wake, 0);
if (mode == S3FWRN5_MODE_FW)
gpio_set_value(phy->gpio_fw_wake, 1);
if (mode != S3FWRN5_MODE_COLD) {
msleep(S3FWRN5_EN_WAIT_TIME);
gpio_set_value(phy->gpio_en, 0);
msleep(S3FWRN5_EN_WAIT_TIME);
}
phy->irq_skip = true; phy->irq_skip = true;
out: out:
mutex_unlock(&phy->mutex); mutex_unlock(&phy->common.mutex);
}
static enum s3fwrn5_mode s3fwrn5_i2c_get_mode(void *phy_id)
{
struct s3fwrn5_i2c_phy *phy = phy_id;
enum s3fwrn5_mode mode;
mutex_lock(&phy->mutex);
mode = phy->mode;
mutex_unlock(&phy->mutex);
return mode;
} }
static int s3fwrn5_i2c_write(void *phy_id, struct sk_buff *skb) static int s3fwrn5_i2c_write(void *phy_id, struct sk_buff *skb)
...@@ -91,7 +46,7 @@ static int s3fwrn5_i2c_write(void *phy_id, struct sk_buff *skb) ...@@ -91,7 +46,7 @@ static int s3fwrn5_i2c_write(void *phy_id, struct sk_buff *skb)
struct s3fwrn5_i2c_phy *phy = phy_id; struct s3fwrn5_i2c_phy *phy = phy_id;
int ret; int ret;
mutex_lock(&phy->mutex); mutex_lock(&phy->common.mutex);
phy->irq_skip = false; phy->irq_skip = false;
...@@ -102,7 +57,7 @@ static int s3fwrn5_i2c_write(void *phy_id, struct sk_buff *skb) ...@@ -102,7 +57,7 @@ static int s3fwrn5_i2c_write(void *phy_id, struct sk_buff *skb)
ret = i2c_master_send(phy->i2c_dev, skb->data, skb->len); ret = i2c_master_send(phy->i2c_dev, skb->data, skb->len);
} }
mutex_unlock(&phy->mutex); mutex_unlock(&phy->common.mutex);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -114,9 +69,9 @@ static int s3fwrn5_i2c_write(void *phy_id, struct sk_buff *skb) ...@@ -114,9 +69,9 @@ static int s3fwrn5_i2c_write(void *phy_id, struct sk_buff *skb)
} }
static const struct s3fwrn5_phy_ops i2c_phy_ops = { static const struct s3fwrn5_phy_ops i2c_phy_ops = {
.set_wake = s3fwrn5_i2c_set_wake, .set_wake = s3fwrn5_phy_set_wake,
.set_mode = s3fwrn5_i2c_set_mode, .set_mode = s3fwrn5_i2c_set_mode,
.get_mode = s3fwrn5_i2c_get_mode, .get_mode = s3fwrn5_phy_get_mode,
.write = s3fwrn5_i2c_write, .write = s3fwrn5_i2c_write,
}; };
...@@ -128,7 +83,7 @@ static int s3fwrn5_i2c_read(struct s3fwrn5_i2c_phy *phy) ...@@ -128,7 +83,7 @@ static int s3fwrn5_i2c_read(struct s3fwrn5_i2c_phy *phy)
char hdr[4]; char hdr[4];
int ret; int ret;
hdr_size = (phy->mode == S3FWRN5_MODE_NCI) ? hdr_size = (phy->common.mode == S3FWRN5_MODE_NCI) ?
NCI_CTRL_HDR_SIZE : S3FWRN5_FW_HDR_SIZE; NCI_CTRL_HDR_SIZE : S3FWRN5_FW_HDR_SIZE;
ret = i2c_master_recv(phy->i2c_dev, hdr, hdr_size); ret = i2c_master_recv(phy->i2c_dev, hdr, hdr_size);
if (ret < 0) if (ret < 0)
...@@ -137,7 +92,7 @@ static int s3fwrn5_i2c_read(struct s3fwrn5_i2c_phy *phy) ...@@ -137,7 +92,7 @@ static int s3fwrn5_i2c_read(struct s3fwrn5_i2c_phy *phy)
if (ret < hdr_size) if (ret < hdr_size)
return -EBADMSG; return -EBADMSG;
data_len = (phy->mode == S3FWRN5_MODE_NCI) ? data_len = (phy->common.mode == S3FWRN5_MODE_NCI) ?
((struct nci_ctrl_hdr *)hdr)->plen : ((struct nci_ctrl_hdr *)hdr)->plen :
((struct s3fwrn5_fw_header *)hdr)->len; ((struct s3fwrn5_fw_header *)hdr)->len;
...@@ -157,24 +112,24 @@ static int s3fwrn5_i2c_read(struct s3fwrn5_i2c_phy *phy) ...@@ -157,24 +112,24 @@ static int s3fwrn5_i2c_read(struct s3fwrn5_i2c_phy *phy)
} }
out: out:
return s3fwrn5_recv_frame(phy->ndev, skb, phy->mode); return s3fwrn5_recv_frame(phy->common.ndev, skb, phy->common.mode);
} }
static irqreturn_t s3fwrn5_i2c_irq_thread_fn(int irq, void *phy_id) static irqreturn_t s3fwrn5_i2c_irq_thread_fn(int irq, void *phy_id)
{ {
struct s3fwrn5_i2c_phy *phy = phy_id; struct s3fwrn5_i2c_phy *phy = phy_id;
if (!phy || !phy->ndev) { if (!phy || !phy->common.ndev) {
WARN_ON_ONCE(1); WARN_ON_ONCE(1);
return IRQ_NONE; return IRQ_NONE;
} }
mutex_lock(&phy->mutex); mutex_lock(&phy->common.mutex);
if (phy->irq_skip) if (phy->irq_skip)
goto out; goto out;
switch (phy->mode) { switch (phy->common.mode) {
case S3FWRN5_MODE_NCI: case S3FWRN5_MODE_NCI:
case S3FWRN5_MODE_FW: case S3FWRN5_MODE_FW:
s3fwrn5_i2c_read(phy); s3fwrn5_i2c_read(phy);
...@@ -184,7 +139,7 @@ static irqreturn_t s3fwrn5_i2c_irq_thread_fn(int irq, void *phy_id) ...@@ -184,7 +139,7 @@ static irqreturn_t s3fwrn5_i2c_irq_thread_fn(int irq, void *phy_id)
} }
out: out:
mutex_unlock(&phy->mutex); mutex_unlock(&phy->common.mutex);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -197,19 +152,23 @@ static int s3fwrn5_i2c_parse_dt(struct i2c_client *client) ...@@ -197,19 +152,23 @@ static int s3fwrn5_i2c_parse_dt(struct i2c_client *client)
if (!np) if (!np)
return -ENODEV; return -ENODEV;
phy->gpio_en = of_get_named_gpio(np, "en-gpios", 0); phy->common.gpio_en = of_get_named_gpio(np, "en-gpios", 0);
if (!gpio_is_valid(phy->gpio_en)) { if (!gpio_is_valid(phy->common.gpio_en)) {
/* Support also deprecated property */ /* Support also deprecated property */
phy->gpio_en = of_get_named_gpio(np, "s3fwrn5,en-gpios", 0); phy->common.gpio_en = of_get_named_gpio(np,
if (!gpio_is_valid(phy->gpio_en)) "s3fwrn5,en-gpios",
0);
if (!gpio_is_valid(phy->common.gpio_en))
return -ENODEV; return -ENODEV;
} }
phy->gpio_fw_wake = of_get_named_gpio(np, "wake-gpios", 0); phy->common.gpio_fw_wake = of_get_named_gpio(np, "wake-gpios", 0);
if (!gpio_is_valid(phy->gpio_fw_wake)) { if (!gpio_is_valid(phy->common.gpio_fw_wake)) {
/* Support also deprecated property */ /* Support also deprecated property */
phy->gpio_fw_wake = of_get_named_gpio(np, "s3fwrn5,fw-gpios", 0); phy->common.gpio_fw_wake = of_get_named_gpio(np,
if (!gpio_is_valid(phy->gpio_fw_wake)) "s3fwrn5,fw-gpios",
0);
if (!gpio_is_valid(phy->common.gpio_fw_wake))
return -ENODEV; return -ENODEV;
} }
...@@ -226,8 +185,8 @@ static int s3fwrn5_i2c_probe(struct i2c_client *client, ...@@ -226,8 +185,8 @@ static int s3fwrn5_i2c_probe(struct i2c_client *client,
if (!phy) if (!phy)
return -ENOMEM; return -ENOMEM;
mutex_init(&phy->mutex); mutex_init(&phy->common.mutex);
phy->mode = S3FWRN5_MODE_COLD; phy->common.mode = S3FWRN5_MODE_COLD;
phy->irq_skip = true; phy->irq_skip = true;
phy->i2c_dev = client; phy->i2c_dev = client;
...@@ -237,17 +196,19 @@ static int s3fwrn5_i2c_probe(struct i2c_client *client, ...@@ -237,17 +196,19 @@ static int s3fwrn5_i2c_probe(struct i2c_client *client,
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = devm_gpio_request_one(&phy->i2c_dev->dev, phy->gpio_en, ret = devm_gpio_request_one(&phy->i2c_dev->dev, phy->common.gpio_en,
GPIOF_OUT_INIT_HIGH, "s3fwrn5_en"); GPIOF_OUT_INIT_HIGH, "s3fwrn5_en");
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = devm_gpio_request_one(&phy->i2c_dev->dev, phy->gpio_fw_wake, ret = devm_gpio_request_one(&phy->i2c_dev->dev,
phy->common.gpio_fw_wake,
GPIOF_OUT_INIT_LOW, "s3fwrn5_fw_wake"); GPIOF_OUT_INIT_LOW, "s3fwrn5_fw_wake");
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = s3fwrn5_probe(&phy->ndev, phy, &phy->i2c_dev->dev, &i2c_phy_ops); ret = s3fwrn5_probe(&phy->common.ndev, phy, &phy->i2c_dev->dev,
&i2c_phy_ops);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -255,7 +216,7 @@ static int s3fwrn5_i2c_probe(struct i2c_client *client, ...@@ -255,7 +216,7 @@ static int s3fwrn5_i2c_probe(struct i2c_client *client,
s3fwrn5_i2c_irq_thread_fn, IRQF_TRIGGER_HIGH | IRQF_ONESHOT, s3fwrn5_i2c_irq_thread_fn, IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
S3FWRN5_I2C_DRIVER_NAME, phy); S3FWRN5_I2C_DRIVER_NAME, phy);
if (ret) if (ret)
s3fwrn5_remove(phy->ndev); s3fwrn5_remove(phy->common.ndev);
return ret; return ret;
} }
...@@ -264,7 +225,7 @@ static int s3fwrn5_i2c_remove(struct i2c_client *client) ...@@ -264,7 +225,7 @@ static int s3fwrn5_i2c_remove(struct i2c_client *client)
{ {
struct s3fwrn5_i2c_phy *phy = i2c_get_clientdata(client); struct s3fwrn5_i2c_phy *phy = i2c_get_clientdata(client);
s3fwrn5_remove(phy->ndev); s3fwrn5_remove(phy->common.ndev);
return 0; return 0;
} }
......
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Link Layer for Samsung S3FWRN5 NCI based Driver
*
* Copyright (C) 2015 Samsung Electrnoics
* Robert Baldyga <r.baldyga@samsung.com>
* Copyright (C) 2020 Samsung Electrnoics
* Bongsu Jeon <bongsu.jeon@samsung.com>
*/
#include <linux/gpio.h>
#include <linux/delay.h>
#include <linux/module.h>
#include "phy_common.h"
void s3fwrn5_phy_set_wake(void *phy_id, bool wake)
{
struct phy_common *phy = phy_id;
mutex_lock(&phy->mutex);
gpio_set_value(phy->gpio_fw_wake, wake);
msleep(S3FWRN5_EN_WAIT_TIME);
mutex_unlock(&phy->mutex);
}
EXPORT_SYMBOL(s3fwrn5_phy_set_wake);
bool s3fwrn5_phy_power_ctrl(struct phy_common *phy, enum s3fwrn5_mode mode)
{
if (phy->mode == mode)
return false;
phy->mode = mode;
gpio_set_value(phy->gpio_en, 1);
gpio_set_value(phy->gpio_fw_wake, 0);
if (mode == S3FWRN5_MODE_FW)
gpio_set_value(phy->gpio_fw_wake, 1);
if (mode != S3FWRN5_MODE_COLD) {
msleep(S3FWRN5_EN_WAIT_TIME);
gpio_set_value(phy->gpio_en, 0);
msleep(S3FWRN5_EN_WAIT_TIME);
}
return true;
}
EXPORT_SYMBOL(s3fwrn5_phy_power_ctrl);
enum s3fwrn5_mode s3fwrn5_phy_get_mode(void *phy_id)
{
struct phy_common *phy = phy_id;
enum s3fwrn5_mode mode;
mutex_lock(&phy->mutex);
mode = phy->mode;
mutex_unlock(&phy->mutex);
return mode;
}
EXPORT_SYMBOL(s3fwrn5_phy_get_mode);
/* SPDX-License-Identifier: GPL-2.0-or-later
*
* Link Layer for Samsung S3FWRN5 NCI based Driver
*
* Copyright (C) 2015 Samsung Electrnoics
* Robert Baldyga <r.baldyga@samsung.com>
* Copyright (C) 2020 Samsung Electrnoics
* Bongsu Jeon <bongsu.jeon@samsung.com>
*/
#ifndef __NFC_S3FWRN5_PHY_COMMON_H
#define __NFC_S3FWRN5_PHY_COMMON_H
#include <linux/mutex.h>
#include <net/nfc/nci_core.h>
#include "s3fwrn5.h"
#define S3FWRN5_EN_WAIT_TIME 20
struct phy_common {
struct nci_dev *ndev;
int gpio_en;
int gpio_fw_wake;
struct mutex mutex;
enum s3fwrn5_mode mode;
};
void s3fwrn5_phy_set_wake(void *phy_id, bool wake);
bool s3fwrn5_phy_power_ctrl(struct phy_common *phy, enum s3fwrn5_mode mode);
enum s3fwrn5_mode s3fwrn5_phy_get_mode(void *phy_id);
#endif /* __NFC_S3FWRN5_PHY_COMMON_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment