root/drivers/i2c/busses/i2c-pasemi.c

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

DEFINITIONS

This source file includes following definitions.
  1. reg_write
  2. reg_read
  3. pasemi_smb_clear
  4. pasemi_smb_waitready
  5. pasemi_i2c_xfer_msg
  6. pasemi_i2c_xfer
  7. pasemi_smb_xfer
  8. pasemi_smb_func
  9. pasemi_smb_probe
  10. pasemi_smb_remove

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Copyright (C) 2006-2007 PA Semi, Inc
   4  *
   5  * SMBus host driver for PA Semi PWRficient
   6  */
   7 
   8 #include <linux/module.h>
   9 #include <linux/pci.h>
  10 #include <linux/kernel.h>
  11 #include <linux/stddef.h>
  12 #include <linux/sched.h>
  13 #include <linux/i2c.h>
  14 #include <linux/delay.h>
  15 #include <linux/slab.h>
  16 #include <linux/io.h>
  17 
  18 static struct pci_driver pasemi_smb_driver;
  19 
  20 struct pasemi_smbus {
  21         struct pci_dev          *dev;
  22         struct i2c_adapter       adapter;
  23         unsigned long            base;
  24         int                      size;
  25 };
  26 
  27 /* Register offsets */
  28 #define REG_MTXFIFO     0x00
  29 #define REG_MRXFIFO     0x04
  30 #define REG_SMSTA       0x14
  31 #define REG_CTL         0x1c
  32 
  33 /* Register defs */
  34 #define MTXFIFO_READ    0x00000400
  35 #define MTXFIFO_STOP    0x00000200
  36 #define MTXFIFO_START   0x00000100
  37 #define MTXFIFO_DATA_M  0x000000ff
  38 
  39 #define MRXFIFO_EMPTY   0x00000100
  40 #define MRXFIFO_DATA_M  0x000000ff
  41 
  42 #define SMSTA_XEN       0x08000000
  43 #define SMSTA_MTN       0x00200000
  44 
  45 #define CTL_MRR         0x00000400
  46 #define CTL_MTR         0x00000200
  47 #define CTL_CLK_M       0x000000ff
  48 
  49 #define CLK_100K_DIV    84
  50 #define CLK_400K_DIV    21
  51 
  52 static inline void reg_write(struct pasemi_smbus *smbus, int reg, int val)
  53 {
  54         dev_dbg(&smbus->dev->dev, "smbus write reg %lx val %08x\n",
  55                 smbus->base + reg, val);
  56         outl(val, smbus->base + reg);
  57 }
  58 
  59 static inline int reg_read(struct pasemi_smbus *smbus, int reg)
  60 {
  61         int ret;
  62         ret = inl(smbus->base + reg);
  63         dev_dbg(&smbus->dev->dev, "smbus read reg %lx val %08x\n",
  64                 smbus->base + reg, ret);
  65         return ret;
  66 }
  67 
  68 #define TXFIFO_WR(smbus, reg)   reg_write((smbus), REG_MTXFIFO, (reg))
  69 #define RXFIFO_RD(smbus)        reg_read((smbus), REG_MRXFIFO)
  70 
  71 static void pasemi_smb_clear(struct pasemi_smbus *smbus)
  72 {
  73         unsigned int status;
  74 
  75         status = reg_read(smbus, REG_SMSTA);
  76         reg_write(smbus, REG_SMSTA, status);
  77 }
  78 
  79 static int pasemi_smb_waitready(struct pasemi_smbus *smbus)
  80 {
  81         int timeout = 10;
  82         unsigned int status;
  83 
  84         status = reg_read(smbus, REG_SMSTA);
  85 
  86         while (!(status & SMSTA_XEN) && timeout--) {
  87                 msleep(1);
  88                 status = reg_read(smbus, REG_SMSTA);
  89         }
  90 
  91         /* Got NACK? */
  92         if (status & SMSTA_MTN)
  93                 return -ENXIO;
  94 
  95         if (timeout < 0) {
  96                 dev_warn(&smbus->dev->dev, "Timeout, status 0x%08x\n", status);
  97                 reg_write(smbus, REG_SMSTA, status);
  98                 return -ETIME;
  99         }
 100 
 101         /* Clear XEN */
 102         reg_write(smbus, REG_SMSTA, SMSTA_XEN);
 103 
 104         return 0;
 105 }
 106 
 107 static int pasemi_i2c_xfer_msg(struct i2c_adapter *adapter,
 108                                struct i2c_msg *msg, int stop)
 109 {
 110         struct pasemi_smbus *smbus = adapter->algo_data;
 111         int read, i, err;
 112         u32 rd;
 113 
 114         read = msg->flags & I2C_M_RD ? 1 : 0;
 115 
 116         TXFIFO_WR(smbus, MTXFIFO_START | i2c_8bit_addr_from_msg(msg));
 117 
 118         if (read) {
 119                 TXFIFO_WR(smbus, msg->len | MTXFIFO_READ |
 120                                  (stop ? MTXFIFO_STOP : 0));
 121 
 122                 err = pasemi_smb_waitready(smbus);
 123                 if (err)
 124                         goto reset_out;
 125 
 126                 for (i = 0; i < msg->len; i++) {
 127                         rd = RXFIFO_RD(smbus);
 128                         if (rd & MRXFIFO_EMPTY) {
 129                                 err = -ENODATA;
 130                                 goto reset_out;
 131                         }
 132                         msg->buf[i] = rd & MRXFIFO_DATA_M;
 133                 }
 134         } else {
 135                 for (i = 0; i < msg->len - 1; i++)
 136                         TXFIFO_WR(smbus, msg->buf[i]);
 137 
 138                 TXFIFO_WR(smbus, msg->buf[msg->len-1] |
 139                           (stop ? MTXFIFO_STOP : 0));
 140         }
 141 
 142         return 0;
 143 
 144  reset_out:
 145         reg_write(smbus, REG_CTL, (CTL_MTR | CTL_MRR |
 146                   (CLK_100K_DIV & CTL_CLK_M)));
 147         return err;
 148 }
 149 
 150 static int pasemi_i2c_xfer(struct i2c_adapter *adapter,
 151                            struct i2c_msg *msgs, int num)
 152 {
 153         struct pasemi_smbus *smbus = adapter->algo_data;
 154         int ret, i;
 155 
 156         pasemi_smb_clear(smbus);
 157 
 158         ret = 0;
 159 
 160         for (i = 0; i < num && !ret; i++)
 161                 ret = pasemi_i2c_xfer_msg(adapter, &msgs[i], (i == (num - 1)));
 162 
 163         return ret ? ret : num;
 164 }
 165 
 166 static int pasemi_smb_xfer(struct i2c_adapter *adapter,
 167                 u16 addr, unsigned short flags, char read_write, u8 command,
 168                 int size, union i2c_smbus_data *data)
 169 {
 170         struct pasemi_smbus *smbus = adapter->algo_data;
 171         unsigned int rd;
 172         int read_flag, err;
 173         int len = 0, i;
 174 
 175         /* All our ops take 8-bit shifted addresses */
 176         addr <<= 1;
 177         read_flag = read_write == I2C_SMBUS_READ;
 178 
 179         pasemi_smb_clear(smbus);
 180 
 181         switch (size) {
 182         case I2C_SMBUS_QUICK:
 183                 TXFIFO_WR(smbus, addr | read_flag | MTXFIFO_START |
 184                           MTXFIFO_STOP);
 185                 break;
 186         case I2C_SMBUS_BYTE:
 187                 TXFIFO_WR(smbus, addr | read_flag | MTXFIFO_START);
 188                 if (read_write)
 189                         TXFIFO_WR(smbus, 1 | MTXFIFO_STOP | MTXFIFO_READ);
 190                 else
 191                         TXFIFO_WR(smbus, MTXFIFO_STOP | command);
 192                 break;
 193         case I2C_SMBUS_BYTE_DATA:
 194                 TXFIFO_WR(smbus, addr | MTXFIFO_START);
 195                 TXFIFO_WR(smbus, command);
 196                 if (read_write) {
 197                         TXFIFO_WR(smbus, addr | I2C_SMBUS_READ | MTXFIFO_START);
 198                         TXFIFO_WR(smbus, 1 | MTXFIFO_READ | MTXFIFO_STOP);
 199                 } else {
 200                         TXFIFO_WR(smbus, MTXFIFO_STOP | data->byte);
 201                 }
 202                 break;
 203         case I2C_SMBUS_WORD_DATA:
 204                 TXFIFO_WR(smbus, addr | MTXFIFO_START);
 205                 TXFIFO_WR(smbus, command);
 206                 if (read_write) {
 207                         TXFIFO_WR(smbus, addr | I2C_SMBUS_READ | MTXFIFO_START);
 208                         TXFIFO_WR(smbus, 2 | MTXFIFO_READ | MTXFIFO_STOP);
 209                 } else {
 210                         TXFIFO_WR(smbus, data->word & MTXFIFO_DATA_M);
 211                         TXFIFO_WR(smbus, MTXFIFO_STOP | (data->word >> 8));
 212                 }
 213                 break;
 214         case I2C_SMBUS_BLOCK_DATA:
 215                 TXFIFO_WR(smbus, addr | MTXFIFO_START);
 216                 TXFIFO_WR(smbus, command);
 217                 if (read_write) {
 218                         TXFIFO_WR(smbus, addr | I2C_SMBUS_READ | MTXFIFO_START);
 219                         TXFIFO_WR(smbus, 1 | MTXFIFO_READ);
 220                         rd = RXFIFO_RD(smbus);
 221                         len = min_t(u8, (rd & MRXFIFO_DATA_M),
 222                                     I2C_SMBUS_BLOCK_MAX);
 223                         TXFIFO_WR(smbus, len | MTXFIFO_READ |
 224                                          MTXFIFO_STOP);
 225                 } else {
 226                         len = min_t(u8, data->block[0], I2C_SMBUS_BLOCK_MAX);
 227                         TXFIFO_WR(smbus, len);
 228                         for (i = 1; i < len; i++)
 229                                 TXFIFO_WR(smbus, data->block[i]);
 230                         TXFIFO_WR(smbus, data->block[len] | MTXFIFO_STOP);
 231                 }
 232                 break;
 233         case I2C_SMBUS_PROC_CALL:
 234                 read_write = I2C_SMBUS_READ;
 235                 TXFIFO_WR(smbus, addr | MTXFIFO_START);
 236                 TXFIFO_WR(smbus, command);
 237                 TXFIFO_WR(smbus, data->word & MTXFIFO_DATA_M);
 238                 TXFIFO_WR(smbus, (data->word >> 8) & MTXFIFO_DATA_M);
 239                 TXFIFO_WR(smbus, addr | I2C_SMBUS_READ | MTXFIFO_START);
 240                 TXFIFO_WR(smbus, 2 | MTXFIFO_STOP | MTXFIFO_READ);
 241                 break;
 242         case I2C_SMBUS_BLOCK_PROC_CALL:
 243                 len = min_t(u8, data->block[0], I2C_SMBUS_BLOCK_MAX - 1);
 244                 read_write = I2C_SMBUS_READ;
 245                 TXFIFO_WR(smbus, addr | MTXFIFO_START);
 246                 TXFIFO_WR(smbus, command);
 247                 TXFIFO_WR(smbus, len);
 248                 for (i = 1; i <= len; i++)
 249                         TXFIFO_WR(smbus, data->block[i]);
 250                 TXFIFO_WR(smbus, addr | I2C_SMBUS_READ);
 251                 TXFIFO_WR(smbus, MTXFIFO_READ | 1);
 252                 rd = RXFIFO_RD(smbus);
 253                 len = min_t(u8, (rd & MRXFIFO_DATA_M),
 254                             I2C_SMBUS_BLOCK_MAX - len);
 255                 TXFIFO_WR(smbus, len | MTXFIFO_READ | MTXFIFO_STOP);
 256                 break;
 257 
 258         default:
 259                 dev_warn(&adapter->dev, "Unsupported transaction %d\n", size);
 260                 return -EINVAL;
 261         }
 262 
 263         err = pasemi_smb_waitready(smbus);
 264         if (err)
 265                 goto reset_out;
 266 
 267         if (read_write == I2C_SMBUS_WRITE)
 268                 return 0;
 269 
 270         switch (size) {
 271         case I2C_SMBUS_BYTE:
 272         case I2C_SMBUS_BYTE_DATA:
 273                 rd = RXFIFO_RD(smbus);
 274                 if (rd & MRXFIFO_EMPTY) {
 275                         err = -ENODATA;
 276                         goto reset_out;
 277                 }
 278                 data->byte = rd & MRXFIFO_DATA_M;
 279                 break;
 280         case I2C_SMBUS_WORD_DATA:
 281         case I2C_SMBUS_PROC_CALL:
 282                 rd = RXFIFO_RD(smbus);
 283                 if (rd & MRXFIFO_EMPTY) {
 284                         err = -ENODATA;
 285                         goto reset_out;
 286                 }
 287                 data->word = rd & MRXFIFO_DATA_M;
 288                 rd = RXFIFO_RD(smbus);
 289                 if (rd & MRXFIFO_EMPTY) {
 290                         err = -ENODATA;
 291                         goto reset_out;
 292                 }
 293                 data->word |= (rd & MRXFIFO_DATA_M) << 8;
 294                 break;
 295         case I2C_SMBUS_BLOCK_DATA:
 296         case I2C_SMBUS_BLOCK_PROC_CALL:
 297                 data->block[0] = len;
 298                 for (i = 1; i <= len; i ++) {
 299                         rd = RXFIFO_RD(smbus);
 300                         if (rd & MRXFIFO_EMPTY) {
 301                                 err = -ENODATA;
 302                                 goto reset_out;
 303                         }
 304                         data->block[i] = rd & MRXFIFO_DATA_M;
 305                 }
 306                 break;
 307         }
 308 
 309         return 0;
 310 
 311  reset_out:
 312         reg_write(smbus, REG_CTL, (CTL_MTR | CTL_MRR |
 313                   (CLK_100K_DIV & CTL_CLK_M)));
 314         return err;
 315 }
 316 
 317 static u32 pasemi_smb_func(struct i2c_adapter *adapter)
 318 {
 319         return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
 320                I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
 321                I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_PROC_CALL |
 322                I2C_FUNC_SMBUS_BLOCK_PROC_CALL | I2C_FUNC_I2C;
 323 }
 324 
 325 static const struct i2c_algorithm smbus_algorithm = {
 326         .master_xfer    = pasemi_i2c_xfer,
 327         .smbus_xfer     = pasemi_smb_xfer,
 328         .functionality  = pasemi_smb_func,
 329 };
 330 
 331 static int pasemi_smb_probe(struct pci_dev *dev,
 332                                       const struct pci_device_id *id)
 333 {
 334         struct pasemi_smbus *smbus;
 335         int error;
 336 
 337         if (!(pci_resource_flags(dev, 0) & IORESOURCE_IO))
 338                 return -ENODEV;
 339 
 340         smbus = kzalloc(sizeof(struct pasemi_smbus), GFP_KERNEL);
 341         if (!smbus)
 342                 return -ENOMEM;
 343 
 344         smbus->dev = dev;
 345         smbus->base = pci_resource_start(dev, 0);
 346         smbus->size = pci_resource_len(dev, 0);
 347 
 348         if (!request_region(smbus->base, smbus->size,
 349                             pasemi_smb_driver.name)) {
 350                 error = -EBUSY;
 351                 goto out_kfree;
 352         }
 353 
 354         smbus->adapter.owner = THIS_MODULE;
 355         snprintf(smbus->adapter.name, sizeof(smbus->adapter.name),
 356                  "PA Semi SMBus adapter at 0x%lx", smbus->base);
 357         smbus->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
 358         smbus->adapter.algo = &smbus_algorithm;
 359         smbus->adapter.algo_data = smbus;
 360 
 361         /* set up the sysfs linkage to our parent device */
 362         smbus->adapter.dev.parent = &dev->dev;
 363 
 364         reg_write(smbus, REG_CTL, (CTL_MTR | CTL_MRR |
 365                   (CLK_100K_DIV & CTL_CLK_M)));
 366 
 367         error = i2c_add_adapter(&smbus->adapter);
 368         if (error)
 369                 goto out_release_region;
 370 
 371         pci_set_drvdata(dev, smbus);
 372 
 373         return 0;
 374 
 375  out_release_region:
 376         release_region(smbus->base, smbus->size);
 377  out_kfree:
 378         kfree(smbus);
 379         return error;
 380 }
 381 
 382 static void pasemi_smb_remove(struct pci_dev *dev)
 383 {
 384         struct pasemi_smbus *smbus = pci_get_drvdata(dev);
 385 
 386         i2c_del_adapter(&smbus->adapter);
 387         release_region(smbus->base, smbus->size);
 388         kfree(smbus);
 389 }
 390 
 391 static const struct pci_device_id pasemi_smb_ids[] = {
 392         { PCI_DEVICE(0x1959, 0xa003) },
 393         { 0, }
 394 };
 395 
 396 MODULE_DEVICE_TABLE(pci, pasemi_smb_ids);
 397 
 398 static struct pci_driver pasemi_smb_driver = {
 399         .name           = "i2c-pasemi",
 400         .id_table       = pasemi_smb_ids,
 401         .probe          = pasemi_smb_probe,
 402         .remove         = pasemi_smb_remove,
 403 };
 404 
 405 module_pci_driver(pasemi_smb_driver);
 406 
 407 MODULE_LICENSE("GPL");
 408 MODULE_AUTHOR ("Olof Johansson <olof@lixom.net>");
 409 MODULE_DESCRIPTION("PA Semi PWRficient SMBus driver");

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