1 /* 2 * I2C Link Layer for Samsung S3FWRN5 NCI based Driver 3 * 4 * Copyright (C) 2015 Samsung Electrnoics 5 * Robert Baldyga <r.baldyga@samsung.com> 6 * 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. 10 * 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. 15 * 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/>. 18 */ 19 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> 26 27 #include <net/nfc/nfc.h> 28 29 #include "s3fwrn5.h" 30 31 #define S3FWRN5_I2C_DRIVER_NAME "s3fwrn5_i2c" 32 33 #define S3FWRN5_I2C_MAX_PAYLOAD 32 34 #define S3FWRN5_EN_WAIT_TIME 150 35 36 struct s3fwrn5_i2c_phy { 37 struct i2c_client *i2c_dev; 38 struct nci_dev *ndev; 39 40 unsigned int gpio_en; 41 unsigned int gpio_fw_wake; 42 43 struct mutex mutex; 44 45 enum s3fwrn5_mode mode; 46 unsigned int irq_skip:1; 47 }; 48 49 static void s3fwrn5_i2c_set_wake(void *phy_id, bool wake) 50 { 51 struct s3fwrn5_i2c_phy *phy = phy_id; 52 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); 57 } 58 59 static void s3fwrn5_i2c_set_mode(void *phy_id, enum s3fwrn5_mode mode) 60 { 61 struct s3fwrn5_i2c_phy *phy = phy_id; 62 63 mutex_lock(&phy->mutex); 64 65 if (phy->mode == mode) 66 goto out; 67 68 phy->mode = mode; 69 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); 74 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); 79 } 80 81 phy->irq_skip = true; 82 83 out: 84 mutex_unlock(&phy->mutex); 85 } 86 87 static enum s3fwrn5_mode s3fwrn5_i2c_get_mode(void *phy_id) 88 { 89 struct s3fwrn5_i2c_phy *phy = phy_id; 90 enum s3fwrn5_mode mode; 91 92 mutex_lock(&phy->mutex); 93 94 mode = phy->mode; 95 96 mutex_unlock(&phy->mutex); 97 98 return mode; 99 } 100 101 static int s3fwrn5_i2c_write(void *phy_id, struct sk_buff *skb) 102 { 103 struct s3fwrn5_i2c_phy *phy = phy_id; 104 int ret; 105 106 mutex_lock(&phy->mutex); 107 108 phy->irq_skip = false; 109 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); 115 } 116 117 mutex_unlock(&phy->mutex); 118 119 if (ret < 0) 120 return ret; 121 122 if (ret != skb->len) 123 return -EREMOTEIO; 124 125 return 0; 126 } 127 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, 133 }; 134 135 static int s3fwrn5_i2c_read(struct s3fwrn5_i2c_phy *phy) 136 { 137 struct sk_buff *skb; 138 size_t hdr_size; 139 size_t data_len; 140 char hdr[4]; 141 int ret; 142 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); 146 if (ret < 0) 147 return ret; 148 149 if (ret < hdr_size) 150 return -EBADMSG; 151 152 data_len = (phy->mode == S3FWRN5_MODE_NCI) ? 153 ((struct nci_ctrl_hdr *)hdr)->plen : 154 ((struct s3fwrn5_fw_header *)hdr)->len; 155 156 skb = alloc_skb(hdr_size + data_len, GFP_KERNEL); 157 if (!skb) 158 return -ENOMEM; 159 160 memcpy(skb_put(skb, hdr_size), hdr, hdr_size); 161 162 if (data_len == 0) 163 goto out; 164 165 ret = i2c_master_recv(phy->i2c_dev, skb_put(skb, data_len), data_len); 166 if (ret != data_len) { 167 kfree_skb(skb); 168 return -EBADMSG; 169 } 170 171 out: 172 return s3fwrn5_recv_frame(phy->ndev, skb, phy->mode); 173 } 174 175 static irqreturn_t s3fwrn5_i2c_irq_thread_fn(int irq, void *phy_id) 176 { 177 struct s3fwrn5_i2c_phy *phy = phy_id; 178 int ret = 0; 179 180 if (!phy || !phy->ndev) { 181 WARN_ON_ONCE(1); 182 return IRQ_NONE; 183 } 184 185 mutex_lock(&phy->mutex); 186 187 if (phy->irq_skip) 188 goto out; 189 190 switch (phy->mode) { 191 case S3FWRN5_MODE_NCI: 192 case S3FWRN5_MODE_FW: 193 ret = s3fwrn5_i2c_read(phy); 194 break; 195 case S3FWRN5_MODE_COLD: 196 ret = -EREMOTEIO; 197 break; 198 } 199 200 out: 201 mutex_unlock(&phy->mutex); 202 203 return IRQ_HANDLED; 204 } 205 206 static int s3fwrn5_i2c_parse_dt(struct i2c_client *client) 207 { 208 struct s3fwrn5_i2c_phy *phy = i2c_get_clientdata(client); 209 struct device_node *np = client->dev.of_node; 210 211 if (!np) 212 return -ENODEV; 213 214 phy->gpio_en = of_get_named_gpio(np, "s3fwrn5,en-gpios", 0); 215 if (!gpio_is_valid(phy->gpio_en)) 216 return -ENODEV; 217 218 phy->gpio_fw_wake = of_get_named_gpio(np, "s3fwrn5,fw-gpios", 0); 219 if (!gpio_is_valid(phy->gpio_fw_wake)) 220 return -ENODEV; 221 222 return 0; 223 } 224 225 static int s3fwrn5_i2c_probe(struct i2c_client *client, 226 const struct i2c_device_id *id) 227 { 228 struct s3fwrn5_i2c_phy *phy; 229 int ret; 230 231 phy = devm_kzalloc(&client->dev, sizeof(*phy), GFP_KERNEL); 232 if (!phy) 233 return -ENOMEM; 234 235 mutex_init(&phy->mutex); 236 phy->mode = S3FWRN5_MODE_COLD; 237 phy->irq_skip = true; 238 239 phy->i2c_dev = client; 240 i2c_set_clientdata(client, phy); 241 242 ret = s3fwrn5_i2c_parse_dt(client); 243 if (ret < 0) 244 return ret; 245 246 ret = devm_gpio_request_one(&phy->i2c_dev->dev, phy->gpio_en, 247 GPIOF_OUT_INIT_HIGH, "s3fwrn5_en"); 248 if (ret < 0) 249 return ret; 250 251 ret = devm_gpio_request_one(&phy->i2c_dev->dev, phy->gpio_fw_wake, 252 GPIOF_OUT_INIT_LOW, "s3fwrn5_fw_wake"); 253 if (ret < 0) 254 return ret; 255 256 ret = s3fwrn5_probe(&phy->ndev, phy, &phy->i2c_dev->dev, &i2c_phy_ops, 257 S3FWRN5_I2C_MAX_PAYLOAD); 258 if (ret < 0) 259 return ret; 260 261 ret = request_threaded_irq(phy->i2c_dev->irq, NULL, 262 s3fwrn5_i2c_irq_thread_fn, IRQF_TRIGGER_HIGH | IRQF_ONESHOT, 263 S3FWRN5_I2C_DRIVER_NAME, phy); 264 if (ret) 265 s3fwrn5_remove(phy->ndev); 266 267 return ret; 268 } 269 270 static int s3fwrn5_i2c_remove(struct i2c_client *client) 271 { 272 struct s3fwrn5_i2c_phy *phy = i2c_get_clientdata(client); 273 274 s3fwrn5_remove(phy->ndev); 275 276 return 0; 277 } 278 279 static struct i2c_device_id s3fwrn5_i2c_id_table[] = { 280 {S3FWRN5_I2C_DRIVER_NAME, 0}, 281 {} 282 }; 283 MODULE_DEVICE_TABLE(i2c, s3fwrn5_i2c_id_table); 284 285 static const struct of_device_id of_s3fwrn5_i2c_match[] = { 286 { .compatible = "samsung,s3fwrn5-i2c", }, 287 {} 288 }; 289 MODULE_DEVICE_TABLE(of, of_s3fwrn5_i2c_match); 290 291 static struct i2c_driver s3fwrn5_i2c_driver = { 292 .driver = { 293 .owner = THIS_MODULE, 294 .name = S3FWRN5_I2C_DRIVER_NAME, 295 .of_match_table = of_match_ptr(of_s3fwrn5_i2c_match), 296 }, 297 .probe = s3fwrn5_i2c_probe, 298 .remove = s3fwrn5_i2c_remove, 299 .id_table = s3fwrn5_i2c_id_table, 300 }; 301 302 module_i2c_driver(s3fwrn5_i2c_driver); 303 304 MODULE_LICENSE("GPL"); 305 MODULE_DESCRIPTION("I2C driver for Samsung S3FWRN5"); 306 MODULE_AUTHOR("Robert Baldyga <r.baldyga@samsung.com>"); 307