root/drivers/nfc/s3fwrn5/i2c.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. s3fwrn5_i2c_set_wake
  2. s3fwrn5_i2c_set_mode
  3. s3fwrn5_i2c_get_mode
  4. s3fwrn5_i2c_write
  5. s3fwrn5_i2c_read
  6. s3fwrn5_i2c_irq_thread_fn
  7. s3fwrn5_i2c_parse_dt
  8. s3fwrn5_i2c_probe
  9. s3fwrn5_i2c_remove

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

/* [<][>][^][v][top][bottom][index][help] */