Version:  2.0.40 2.2.26 2.4.37 2.6.39 3.0 3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8 3.9 3.10 3.11 3.12 3.13 3.14 3.15

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

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

This page was automatically generated by LXR 0.3.1 (source).  •  Linux is a registered trademark of Linus Torvalds  •  Contact us