1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * I2C Link Layer for Samsung S3FWRN5 NCI based Driver
5 * Copyright (C) 2015 Samsung Electrnoics
6 * Robert Baldyga <r.baldyga@samsung.com>
10 #include <linux/i2c.h>
11 #include <linux/gpio.h>
12 #include <linux/delay.h>
13 #include <linux/of_gpio.h>
14 #include <linux/of_irq.h>
15 #include <linux/module.h>
17 #include <net/nfc/nfc.h>
19 #include "phy_common.h"
21 #define S3FWRN5_I2C_DRIVER_NAME "s3fwrn5_i2c"
23 struct s3fwrn5_i2c_phy
{
24 struct phy_common common
;
25 struct i2c_client
*i2c_dev
;
28 unsigned int irq_skip
:1;
31 static void s3fwrn5_i2c_set_mode(void *phy_id
, enum s3fwrn5_mode mode
)
33 struct s3fwrn5_i2c_phy
*phy
= phy_id
;
35 mutex_lock(&phy
->common
.mutex
);
37 if (s3fwrn5_phy_power_ctrl(&phy
->common
, mode
) == false)
43 mutex_unlock(&phy
->common
.mutex
);
46 static int s3fwrn5_i2c_write(void *phy_id
, struct sk_buff
*skb
)
48 struct s3fwrn5_i2c_phy
*phy
= phy_id
;
51 mutex_lock(&phy
->common
.mutex
);
53 phy
->irq_skip
= false;
55 ret
= i2c_master_send(phy
->i2c_dev
, skb
->data
, skb
->len
);
56 if (ret
== -EREMOTEIO
) {
57 /* Retry, chip was in standby */
58 usleep_range(110000, 120000);
59 ret
= i2c_master_send(phy
->i2c_dev
, skb
->data
, skb
->len
);
62 mutex_unlock(&phy
->common
.mutex
);
73 static const struct s3fwrn5_phy_ops i2c_phy_ops
= {
74 .set_wake
= s3fwrn5_phy_set_wake
,
75 .set_mode
= s3fwrn5_i2c_set_mode
,
76 .get_mode
= s3fwrn5_phy_get_mode
,
77 .write
= s3fwrn5_i2c_write
,
80 static int s3fwrn5_i2c_read(struct s3fwrn5_i2c_phy
*phy
)
88 hdr_size
= (phy
->common
.mode
== S3FWRN5_MODE_NCI
) ?
89 NCI_CTRL_HDR_SIZE
: S3FWRN5_FW_HDR_SIZE
;
90 ret
= i2c_master_recv(phy
->i2c_dev
, hdr
, hdr_size
);
97 data_len
= (phy
->common
.mode
== S3FWRN5_MODE_NCI
) ?
98 ((struct nci_ctrl_hdr
*)hdr
)->plen
:
99 ((struct s3fwrn5_fw_header
*)hdr
)->len
;
101 skb
= alloc_skb(hdr_size
+ data_len
, GFP_KERNEL
);
105 skb_put_data(skb
, hdr
, hdr_size
);
110 ret
= i2c_master_recv(phy
->i2c_dev
, skb_put(skb
, data_len
), data_len
);
111 if (ret
!= data_len
) {
117 return s3fwrn5_recv_frame(phy
->common
.ndev
, skb
, phy
->common
.mode
);
120 static irqreturn_t
s3fwrn5_i2c_irq_thread_fn(int irq
, void *phy_id
)
122 struct s3fwrn5_i2c_phy
*phy
= phy_id
;
124 if (!phy
|| !phy
->common
.ndev
) {
129 mutex_lock(&phy
->common
.mutex
);
134 switch (phy
->common
.mode
) {
135 case S3FWRN5_MODE_NCI
:
136 case S3FWRN5_MODE_FW
:
137 s3fwrn5_i2c_read(phy
);
139 case S3FWRN5_MODE_COLD
:
144 mutex_unlock(&phy
->common
.mutex
);
149 static int s3fwrn5_i2c_parse_dt(struct i2c_client
*client
)
151 struct s3fwrn5_i2c_phy
*phy
= i2c_get_clientdata(client
);
152 struct device_node
*np
= client
->dev
.of_node
;
157 phy
->common
.gpio_en
= of_get_named_gpio(np
, "en-gpios", 0);
158 if (!gpio_is_valid(phy
->common
.gpio_en
)) {
159 /* Support also deprecated property */
160 phy
->common
.gpio_en
= of_get_named_gpio(np
,
163 if (!gpio_is_valid(phy
->common
.gpio_en
))
167 phy
->common
.gpio_fw_wake
= of_get_named_gpio(np
, "wake-gpios", 0);
168 if (!gpio_is_valid(phy
->common
.gpio_fw_wake
)) {
169 /* Support also deprecated property */
170 phy
->common
.gpio_fw_wake
= of_get_named_gpio(np
,
173 if (!gpio_is_valid(phy
->common
.gpio_fw_wake
))
180 static int s3fwrn5_i2c_probe(struct i2c_client
*client
)
182 struct s3fwrn5_i2c_phy
*phy
;
185 phy
= devm_kzalloc(&client
->dev
, sizeof(*phy
), GFP_KERNEL
);
189 mutex_init(&phy
->common
.mutex
);
190 phy
->common
.mode
= S3FWRN5_MODE_COLD
;
191 phy
->irq_skip
= true;
193 phy
->i2c_dev
= client
;
194 i2c_set_clientdata(client
, phy
);
196 ret
= s3fwrn5_i2c_parse_dt(client
);
200 ret
= devm_gpio_request_one(&phy
->i2c_dev
->dev
, phy
->common
.gpio_en
,
201 GPIOF_OUT_INIT_HIGH
, "s3fwrn5_en");
205 ret
= devm_gpio_request_one(&phy
->i2c_dev
->dev
,
206 phy
->common
.gpio_fw_wake
,
207 GPIOF_OUT_INIT_LOW
, "s3fwrn5_fw_wake");
212 * S3FWRN5 depends on a clock input ("XI" pin) to function properly.
213 * Depending on the hardware configuration this could be an always-on
214 * oscillator or some external clock that must be explicitly enabled.
215 * Make sure the clock is running before starting S3FWRN5.
217 phy
->clk
= devm_clk_get_optional_enabled(&client
->dev
, NULL
);
218 if (IS_ERR(phy
->clk
))
219 return dev_err_probe(&client
->dev
, PTR_ERR(phy
->clk
),
220 "failed to get clock\n");
222 ret
= s3fwrn5_probe(&phy
->common
.ndev
, phy
, &phy
->i2c_dev
->dev
,
227 ret
= devm_request_threaded_irq(&client
->dev
, phy
->i2c_dev
->irq
, NULL
,
228 s3fwrn5_i2c_irq_thread_fn
, IRQF_ONESHOT
,
229 S3FWRN5_I2C_DRIVER_NAME
, phy
);
236 s3fwrn5_remove(phy
->common
.ndev
);
240 static void s3fwrn5_i2c_remove(struct i2c_client
*client
)
242 struct s3fwrn5_i2c_phy
*phy
= i2c_get_clientdata(client
);
244 s3fwrn5_remove(phy
->common
.ndev
);
247 static const struct i2c_device_id s3fwrn5_i2c_id_table
[] = {
248 { S3FWRN5_I2C_DRIVER_NAME
},
251 MODULE_DEVICE_TABLE(i2c
, s3fwrn5_i2c_id_table
);
253 static const struct of_device_id of_s3fwrn5_i2c_match
[] __maybe_unused
= {
254 { .compatible
= "samsung,s3fwrn5-i2c", },
257 MODULE_DEVICE_TABLE(of
, of_s3fwrn5_i2c_match
);
259 static struct i2c_driver s3fwrn5_i2c_driver
= {
261 .name
= S3FWRN5_I2C_DRIVER_NAME
,
262 .of_match_table
= of_match_ptr(of_s3fwrn5_i2c_match
),
264 .probe
= s3fwrn5_i2c_probe
,
265 .remove
= s3fwrn5_i2c_remove
,
266 .id_table
= s3fwrn5_i2c_id_table
,
269 module_i2c_driver(s3fwrn5_i2c_driver
);
271 MODULE_LICENSE("GPL");
272 MODULE_DESCRIPTION("I2C driver for Samsung S3FWRN5");
273 MODULE_AUTHOR("Robert Baldyga <r.baldyga@samsung.com>");