aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/i2c/i2c-stub11
-rw-r--r--drivers/i2c/i2c-stub.c131
2 files changed, 128 insertions, 14 deletions
diff --git a/Documentation/i2c/i2c-stub b/Documentation/i2c/i2c-stub
index a0fe7a04a3bd..a16924fbd289 100644
--- a/Documentation/i2c/i2c-stub
+++ b/Documentation/i2c/i2c-stub
@@ -47,15 +47,18 @@ unsigned long functionality:
47 value 0x1f0000 would only enable the quick, byte and byte data 47 value 0x1f0000 would only enable the quick, byte and byte data
48 commands. 48 commands.
49 49
50u8 bank_reg[10]
51u8 bank_mask[10]
52u8 bank_start[10]
53u8 bank_end[10]:
54 Optional bank settings. They tell which bits in which register
55 select the active bank, as well as the range of banked registers.
56
50CAVEATS: 57CAVEATS:
51 58
52If your target driver polls some byte or word waiting for it to change, the 59If your target driver polls some byte or word waiting for it to change, the
53stub could lock it up. Use i2cset to unlock it. 60stub could lock it up. Use i2cset to unlock it.
54 61
55If the hardware for your driver has banked registers (e.g. Winbond sensors
56chips) this module will not work well - although it could be extended to
57support that pretty easily.
58
59If you spam it hard enough, printk can be lossy. This module really wants 62If you spam it hard enough, printk can be lossy. This module really wants
60something like relayfs. 63something like relayfs.
61 64
diff --git a/drivers/i2c/i2c-stub.c b/drivers/i2c/i2c-stub.c
index ad52f0701198..e815c6067ff3 100644
--- a/drivers/i2c/i2c-stub.c
+++ b/drivers/i2c/i2c-stub.c
@@ -2,7 +2,7 @@
2 i2c-stub.c - I2C/SMBus chip emulator 2 i2c-stub.c - I2C/SMBus chip emulator
3 3
4 Copyright (c) 2004 Mark M. Hoffman <mhoffman@lightlink.com> 4 Copyright (c) 2004 Mark M. Hoffman <mhoffman@lightlink.com>
5 Copyright (C) 2007, 2012 Jean Delvare <jdelvare@suse.de> 5 Copyright (C) 2007-2014 Jean Delvare <jdelvare@suse.de>
6 6
7 This program is free software; you can redistribute it and/or modify 7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by 8 it under the terms of the GNU General Public License as published by
@@ -53,6 +53,24 @@ static unsigned long functionality = STUB_FUNC_DEFAULT;
53module_param(functionality, ulong, S_IRUGO | S_IWUSR); 53module_param(functionality, ulong, S_IRUGO | S_IWUSR);
54MODULE_PARM_DESC(functionality, "Override functionality bitfield"); 54MODULE_PARM_DESC(functionality, "Override functionality bitfield");
55 55
56/* Some chips have banked register ranges */
57
58static u8 bank_reg[MAX_CHIPS];
59module_param_array(bank_reg, byte, NULL, S_IRUGO);
60MODULE_PARM_DESC(bank_reg, "Bank register");
61
62static u8 bank_mask[MAX_CHIPS];
63module_param_array(bank_mask, byte, NULL, S_IRUGO);
64MODULE_PARM_DESC(bank_mask, "Bank value mask");
65
66static u8 bank_start[MAX_CHIPS];
67module_param_array(bank_start, byte, NULL, S_IRUGO);
68MODULE_PARM_DESC(bank_start, "First banked register");
69
70static u8 bank_end[MAX_CHIPS];
71module_param_array(bank_end, byte, NULL, S_IRUGO);
72MODULE_PARM_DESC(bank_end, "Last banked register");
73
56struct smbus_block_data { 74struct smbus_block_data {
57 struct list_head node; 75 struct list_head node;
58 u8 command; 76 u8 command;
@@ -65,6 +83,16 @@ struct stub_chip {
65 u16 words[256]; /* Byte operations use the LSB as per SMBus 83 u16 words[256]; /* Byte operations use the LSB as per SMBus
66 specification */ 84 specification */
67 struct list_head smbus_blocks; 85 struct list_head smbus_blocks;
86
87 /* For chips with banks, extra registers are allocated dynamically */
88 u8 bank_reg;
89 u8 bank_shift;
90 u8 bank_mask;
91 u8 bank_sel; /* Currently selected bank */
92 u8 bank_start;
93 u8 bank_end;
94 u16 bank_size;
95 u16 *bank_words; /* Room for bank_mask * bank_size registers */
68}; 96};
69 97
70static struct stub_chip *stub_chips; 98static struct stub_chip *stub_chips;
@@ -92,6 +120,17 @@ static struct smbus_block_data *stub_find_block(struct device *dev,
92 return rb; 120 return rb;
93} 121}
94 122
123static u16 *stub_get_wordp(struct stub_chip *chip, u8 offset)
124{
125 if (chip->bank_sel &&
126 offset >= chip->bank_start && offset <= chip->bank_end)
127 return chip->bank_words +
128 (chip->bank_sel - 1) * chip->bank_size +
129 offset - chip->bank_start;
130 else
131 return chip->words + offset;
132}
133
95/* Return negative errno on error. */ 134/* Return negative errno on error. */
96static s32 stub_xfer(struct i2c_adapter *adap, u16 addr, unsigned short flags, 135static s32 stub_xfer(struct i2c_adapter *adap, u16 addr, unsigned short flags,
97 char read_write, u8 command, int size, union i2c_smbus_data *data) 136 char read_write, u8 command, int size, union i2c_smbus_data *data)
@@ -100,6 +139,7 @@ static s32 stub_xfer(struct i2c_adapter *adap, u16 addr, unsigned short flags,
100 int i, len; 139 int i, len;
101 struct stub_chip *chip = NULL; 140 struct stub_chip *chip = NULL;
102 struct smbus_block_data *b; 141 struct smbus_block_data *b;
142 u16 *wordp;
103 143
104 /* Search for the right chip */ 144 /* Search for the right chip */
105 for (i = 0; i < stub_chips_nr; i++) { 145 for (i = 0; i < stub_chips_nr; i++) {
@@ -125,7 +165,8 @@ static s32 stub_xfer(struct i2c_adapter *adap, u16 addr, unsigned short flags,
125 "smbus byte - addr 0x%02x, wrote 0x%02x.\n", 165 "smbus byte - addr 0x%02x, wrote 0x%02x.\n",
126 addr, command); 166 addr, command);
127 } else { 167 } else {
128 data->byte = chip->words[chip->pointer++] & 0xff; 168 wordp = stub_get_wordp(chip, chip->pointer++);
169 data->byte = *wordp & 0xff;
129 dev_dbg(&adap->dev, 170 dev_dbg(&adap->dev,
130 "smbus byte - addr 0x%02x, read 0x%02x.\n", 171 "smbus byte - addr 0x%02x, read 0x%02x.\n",
131 addr, data->byte); 172 addr, data->byte);
@@ -135,14 +176,25 @@ static s32 stub_xfer(struct i2c_adapter *adap, u16 addr, unsigned short flags,
135 break; 176 break;
136 177
137 case I2C_SMBUS_BYTE_DATA: 178 case I2C_SMBUS_BYTE_DATA:
179 wordp = stub_get_wordp(chip, command);
138 if (read_write == I2C_SMBUS_WRITE) { 180 if (read_write == I2C_SMBUS_WRITE) {
139 chip->words[command] &= 0xff00; 181 *wordp &= 0xff00;
140 chip->words[command] |= data->byte; 182 *wordp |= data->byte;
141 dev_dbg(&adap->dev, 183 dev_dbg(&adap->dev,
142 "smbus byte data - addr 0x%02x, wrote 0x%02x at 0x%02x.\n", 184 "smbus byte data - addr 0x%02x, wrote 0x%02x at 0x%02x.\n",
143 addr, data->byte, command); 185 addr, data->byte, command);
186
187 /* Set the bank as needed */
188 if (chip->bank_words && command == chip->bank_reg) {
189 chip->bank_sel =
190 (data->byte >> chip->bank_shift)
191 & chip->bank_mask;
192 dev_dbg(&adap->dev,
193 "switching to bank %u.\n",
194 chip->bank_sel);
195 }
144 } else { 196 } else {
145 data->byte = chip->words[command] & 0xff; 197 data->byte = *wordp & 0xff;
146 dev_dbg(&adap->dev, 198 dev_dbg(&adap->dev,
147 "smbus byte data - addr 0x%02x, read 0x%02x at 0x%02x.\n", 199 "smbus byte data - addr 0x%02x, read 0x%02x at 0x%02x.\n",
148 addr, data->byte, command); 200 addr, data->byte, command);
@@ -153,13 +205,14 @@ static s32 stub_xfer(struct i2c_adapter *adap, u16 addr, unsigned short flags,
153 break; 205 break;
154 206
155 case I2C_SMBUS_WORD_DATA: 207 case I2C_SMBUS_WORD_DATA:
208 wordp = stub_get_wordp(chip, command);
156 if (read_write == I2C_SMBUS_WRITE) { 209 if (read_write == I2C_SMBUS_WRITE) {
157 chip->words[command] = data->word; 210 *wordp = data->word;
158 dev_dbg(&adap->dev, 211 dev_dbg(&adap->dev,
159 "smbus word data - addr 0x%02x, wrote 0x%04x at 0x%02x.\n", 212 "smbus word data - addr 0x%02x, wrote 0x%04x at 0x%02x.\n",
160 addr, data->word, command); 213 addr, data->word, command);
161 } else { 214 } else {
162 data->word = chip->words[command]; 215 data->word = *wordp;
163 dev_dbg(&adap->dev, 216 dev_dbg(&adap->dev,
164 "smbus word data - addr 0x%02x, read 0x%04x at 0x%02x.\n", 217 "smbus word data - addr 0x%02x, read 0x%04x at 0x%02x.\n",
165 addr, data->word, command); 218 addr, data->word, command);
@@ -169,6 +222,10 @@ static s32 stub_xfer(struct i2c_adapter *adap, u16 addr, unsigned short flags,
169 break; 222 break;
170 223
171 case I2C_SMBUS_I2C_BLOCK_DATA: 224 case I2C_SMBUS_I2C_BLOCK_DATA:
225 /*
226 * We ignore banks here, because banked chips don't use I2C
227 * block transfers
228 */
172 len = data->block[0]; 229 len = data->block[0];
173 if (read_write == I2C_SMBUS_WRITE) { 230 if (read_write == I2C_SMBUS_WRITE) {
174 for (i = 0; i < len; i++) { 231 for (i = 0; i < len; i++) {
@@ -192,6 +249,10 @@ static s32 stub_xfer(struct i2c_adapter *adap, u16 addr, unsigned short flags,
192 break; 249 break;
193 250
194 case I2C_SMBUS_BLOCK_DATA: 251 case I2C_SMBUS_BLOCK_DATA:
252 /*
253 * We ignore banks here, because chips typically don't use both
254 * banks and SMBus block transfers
255 */
195 b = stub_find_block(&adap->dev, chip, command, false); 256 b = stub_find_block(&adap->dev, chip, command, false);
196 if (read_write == I2C_SMBUS_WRITE) { 257 if (read_write == I2C_SMBUS_WRITE) {
197 len = data->block[0]; 258 len = data->block[0];
@@ -262,6 +323,43 @@ static struct i2c_adapter stub_adapter = {
262 .name = "SMBus stub driver", 323 .name = "SMBus stub driver",
263}; 324};
264 325
326static int __init i2c_stub_allocate_banks(int i)
327{
328 struct stub_chip *chip = stub_chips + i;
329
330 chip->bank_reg = bank_reg[i];
331 chip->bank_start = bank_start[i];
332 chip->bank_end = bank_end[i];
333 chip->bank_size = bank_end[i] - bank_start[i] + 1;
334
335 /* We assume that all bits in the mask are contiguous */
336 chip->bank_mask = bank_mask[i];
337 while (!(chip->bank_mask & 1)) {
338 chip->bank_shift++;
339 chip->bank_mask >>= 1;
340 }
341
342 chip->bank_words = kzalloc(chip->bank_mask * chip->bank_size *
343 sizeof(u16), GFP_KERNEL);
344 if (!chip->bank_words)
345 return -ENOMEM;
346
347 pr_debug("i2c-stub: Allocated %u banks of %u words each (registers 0x%02x to 0x%02x)\n",
348 chip->bank_mask, chip->bank_size, chip->bank_start,
349 chip->bank_end);
350
351 return 0;
352}
353
354static void i2c_stub_free(void)
355{
356 int i;
357
358 for (i = 0; i < stub_chips_nr; i++)
359 kfree(stub_chips[i].bank_words);
360 kfree(stub_chips);
361}
362
265static int __init i2c_stub_init(void) 363static int __init i2c_stub_init(void)
266{ 364{
267 int i, ret; 365 int i, ret;
@@ -289,19 +387,32 @@ static int __init i2c_stub_init(void)
289 pr_err("i2c-stub: Out of memory\n"); 387 pr_err("i2c-stub: Out of memory\n");
290 return -ENOMEM; 388 return -ENOMEM;
291 } 389 }
292 for (i = 0; i < stub_chips_nr; i++) 390 for (i = 0; i < stub_chips_nr; i++) {
293 INIT_LIST_HEAD(&stub_chips[i].smbus_blocks); 391 INIT_LIST_HEAD(&stub_chips[i].smbus_blocks);
294 392
393 /* Allocate extra memory for banked register ranges */
394 if (bank_mask[i]) {
395 ret = i2c_stub_allocate_banks(i);
396 if (ret)
397 goto fail_free;
398 }
399 }
400
295 ret = i2c_add_adapter(&stub_adapter); 401 ret = i2c_add_adapter(&stub_adapter);
296 if (ret) 402 if (ret)
297 kfree(stub_chips); 403 goto fail_free;
404
405 return 0;
406
407 fail_free:
408 i2c_stub_free();
298 return ret; 409 return ret;
299} 410}
300 411
301static void __exit i2c_stub_exit(void) 412static void __exit i2c_stub_exit(void)
302{ 413{
303 i2c_del_adapter(&stub_adapter); 414 i2c_del_adapter(&stub_adapter);
304 kfree(stub_chips); 415 i2c_stub_free();
305} 416}
306 417
307MODULE_AUTHOR("Mark M. Hoffman <mhoffman@lightlink.com>"); 418MODULE_AUTHOR("Mark M. Hoffman <mhoffman@lightlink.com>");