2 * I2C Link Layer for Samsung S3FWRN5 NCI based Driver
4 * Copyright (C) 2015 Samsung Electrnoics
5 * Robert Baldyga <r.baldyga@samsung.com>
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms and conditions of the GNU General Public License,
9 * version 2 or later, as published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
20 #include <linux/i2c.h>
21 #include <linux/gpio.h>
22 #include <linux/delay.h>
23 #include <linux/of_gpio.h>
24 #include <linux/of_irq.h>
25 #include <linux/module.h>
27 #include <net/nfc/nfc.h>
31 #define S3FWRN5_I2C_DRIVER_NAME "s3fwrn5_i2c"
33 #define S3FWRN5_I2C_MAX_PAYLOAD 32
34 #define S3FWRN5_EN_WAIT_TIME 150
36 struct s3fwrn5_i2c_phy
{
37 struct i2c_client
*i2c_dev
;
41 unsigned int gpio_fw_wake
;
45 enum s3fwrn5_mode mode
;
46 unsigned int irq_skip
:1;
49 static void s3fwrn5_i2c_set_wake(void *phy_id
, bool wake
)
51 struct s3fwrn5_i2c_phy
*phy
= phy_id
;
53 mutex_lock(&phy
->mutex
);
54 gpio_set_value(phy
->gpio_fw_wake
, wake
);
55 msleep(S3FWRN5_EN_WAIT_TIME
/2);
56 mutex_unlock(&phy
->mutex
);
59 static void s3fwrn5_i2c_set_mode(void *phy_id
, enum s3fwrn5_mode mode
)
61 struct s3fwrn5_i2c_phy
*phy
= phy_id
;
63 mutex_lock(&phy
->mutex
);
65 if (phy
->mode
== mode
)
70 gpio_set_value(phy
->gpio_en
, 1);
71 gpio_set_value(phy
->gpio_fw_wake
, 0);
72 if (mode
== S3FWRN5_MODE_FW
)
73 gpio_set_value(phy
->gpio_fw_wake
, 1);
75 if (mode
!= S3FWRN5_MODE_COLD
) {
76 msleep(S3FWRN5_EN_WAIT_TIME
);
77 gpio_set_value(phy
->gpio_en
, 0);
78 msleep(S3FWRN5_EN_WAIT_TIME
/2);
84 mutex_unlock(&phy
->mutex
);
87 static enum s3fwrn5_mode
s3fwrn5_i2c_get_mode(void *phy_id
)
89 struct s3fwrn5_i2c_phy
*phy
= phy_id
;
90 enum s3fwrn5_mode mode
;
92 mutex_lock(&phy
->mutex
);
96 mutex_unlock(&phy
->mutex
);
101 static int s3fwrn5_i2c_write(void *phy_id
, struct sk_buff
*skb
)
103 struct s3fwrn5_i2c_phy
*phy
= phy_id
;
106 mutex_lock(&phy
->mutex
);
108 phy
->irq_skip
= false;
110 ret
= i2c_master_send(phy
->i2c_dev
, skb
->data
, skb
->len
);
111 if (ret
== -EREMOTEIO
) {
112 /* Retry, chip was in standby */
113 usleep_range(110000, 120000);
114 ret
= i2c_master_send(phy
->i2c_dev
, skb
->data
, skb
->len
);
117 mutex_unlock(&phy
->mutex
);
128 static struct s3fwrn5_phy_ops i2c_phy_ops
= {
129 .set_wake
= s3fwrn5_i2c_set_wake
,
130 .set_mode
= s3fwrn5_i2c_set_mode
,
131 .get_mode
= s3fwrn5_i2c_get_mode
,
132 .write
= s3fwrn5_i2c_write
,
135 static int s3fwrn5_i2c_read(struct s3fwrn5_i2c_phy
*phy
)
143 hdr_size
= (phy
->mode
== S3FWRN5_MODE_NCI
) ?
144 NCI_CTRL_HDR_SIZE
: S3FWRN5_FW_HDR_SIZE
;
145 ret
= i2c_master_recv(phy
->i2c_dev
, hdr
, hdr_size
);
152 data_len
= (phy
->mode
== S3FWRN5_MODE_NCI
) ?
153 ((struct nci_ctrl_hdr
*)hdr
)->plen
:
154 ((struct s3fwrn5_fw_header
*)hdr
)->len
;
156 skb
= alloc_skb(hdr_size
+ data_len
, GFP_KERNEL
);
160 memcpy(skb_put(skb
, hdr_size
), hdr
, hdr_size
);
165 ret
= i2c_master_recv(phy
->i2c_dev
, skb_put(skb
, data_len
), data_len
);
166 if (ret
!= data_len
) {
172 return s3fwrn5_recv_frame(phy
->ndev
, skb
, phy
->mode
);
175 static irqreturn_t
s3fwrn5_i2c_irq_thread_fn(int irq
, void *phy_id
)
177 struct s3fwrn5_i2c_phy
*phy
= phy_id
;
180 if (!phy
|| !phy
->ndev
) {
185 mutex_lock(&phy
->mutex
);
191 case S3FWRN5_MODE_NCI
:
192 case S3FWRN5_MODE_FW
:
193 ret
= s3fwrn5_i2c_read(phy
);
195 case S3FWRN5_MODE_COLD
:
201 mutex_unlock(&phy
->mutex
);
206 static int s3fwrn5_i2c_parse_dt(struct i2c_client
*client
)
208 struct s3fwrn5_i2c_phy
*phy
= i2c_get_clientdata(client
);
209 struct device_node
*np
= client
->dev
.of_node
;
214 phy
->gpio_en
= of_get_named_gpio(np
, "s3fwrn5,en-gpios", 0);
215 if (!gpio_is_valid(phy
->gpio_en
))
218 phy
->gpio_fw_wake
= of_get_named_gpio(np
, "s3fwrn5,fw-gpios", 0);
219 if (!gpio_is_valid(phy
->gpio_fw_wake
))
225 static int s3fwrn5_i2c_probe(struct i2c_client
*client
,
226 const struct i2c_device_id
*id
)
228 struct s3fwrn5_i2c_phy
*phy
;
231 phy
= devm_kzalloc(&client
->dev
, sizeof(*phy
), GFP_KERNEL
);
235 mutex_init(&phy
->mutex
);
236 phy
->mode
= S3FWRN5_MODE_COLD
;
237 phy
->irq_skip
= true;
239 phy
->i2c_dev
= client
;
240 i2c_set_clientdata(client
, phy
);
242 ret
= s3fwrn5_i2c_parse_dt(client
);
246 ret
= devm_gpio_request_one(&phy
->i2c_dev
->dev
, phy
->gpio_en
,
247 GPIOF_OUT_INIT_HIGH
, "s3fwrn5_en");
251 ret
= devm_gpio_request_one(&phy
->i2c_dev
->dev
, phy
->gpio_fw_wake
,
252 GPIOF_OUT_INIT_LOW
, "s3fwrn5_fw_wake");
256 ret
= s3fwrn5_probe(&phy
->ndev
, phy
, &phy
->i2c_dev
->dev
, &i2c_phy_ops
,
257 S3FWRN5_I2C_MAX_PAYLOAD
);
261 ret
= devm_request_threaded_irq(&client
->dev
, phy
->i2c_dev
->irq
, NULL
,
262 s3fwrn5_i2c_irq_thread_fn
, IRQF_TRIGGER_HIGH
| IRQF_ONESHOT
,
263 S3FWRN5_I2C_DRIVER_NAME
, phy
);
265 s3fwrn5_remove(phy
->ndev
);
270 static int s3fwrn5_i2c_remove(struct i2c_client
*client
)
272 struct s3fwrn5_i2c_phy
*phy
= i2c_get_clientdata(client
);
274 s3fwrn5_remove(phy
->ndev
);
279 static struct i2c_device_id s3fwrn5_i2c_id_table
[] = {
280 {S3FWRN5_I2C_DRIVER_NAME
, 0},
283 MODULE_DEVICE_TABLE(i2c
, s3fwrn5_i2c_id_table
);
285 static const struct of_device_id of_s3fwrn5_i2c_match
[] = {
286 { .compatible
= "samsung,s3fwrn5-i2c", },
289 MODULE_DEVICE_TABLE(of
, of_s3fwrn5_i2c_match
);
291 static struct i2c_driver s3fwrn5_i2c_driver
= {
293 .owner
= THIS_MODULE
,
294 .name
= S3FWRN5_I2C_DRIVER_NAME
,
295 .of_match_table
= of_match_ptr(of_s3fwrn5_i2c_match
),
297 .probe
= s3fwrn5_i2c_probe
,
298 .remove
= s3fwrn5_i2c_remove
,
299 .id_table
= s3fwrn5_i2c_id_table
,
302 module_i2c_driver(s3fwrn5_i2c_driver
);
304 MODULE_LICENSE("GPL");
305 MODULE_DESCRIPTION("I2C driver for Samsung S3FWRN5");
306 MODULE_AUTHOR("Robert Baldyga <r.baldyga@samsung.com>");