1*c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
231d178bfSJean Delvare /*
331d178bfSJean Delvare i2c-stub.c - I2C/SMBus chip emulator
431d178bfSJean Delvare
531d178bfSJean Delvare Copyright (c) 2004 Mark M. Hoffman <mhoffman@lightlink.com>
62408c17fSJean Delvare Copyright (C) 2007-2014 Jean Delvare <jdelvare@suse.de>
731d178bfSJean Delvare
831d178bfSJean Delvare */
931d178bfSJean Delvare
106c427787SWolfram Sang #define pr_fmt(fmt) "i2c-stub: " fmt
1131d178bfSJean Delvare
1231d178bfSJean Delvare #include <linux/errno.h>
1331d178bfSJean Delvare #include <linux/i2c.h>
149f8f53a6SWolfram Sang #include <linux/init.h>
159f8f53a6SWolfram Sang #include <linux/kernel.h>
166f16b75aSGuenter Roeck #include <linux/list.h>
179f8f53a6SWolfram Sang #include <linux/module.h>
189f8f53a6SWolfram Sang #include <linux/slab.h>
1931d178bfSJean Delvare
2031d178bfSJean Delvare #define MAX_CHIPS 10
216f16b75aSGuenter Roeck
226f16b75aSGuenter Roeck /*
236f16b75aSGuenter Roeck * Support for I2C_FUNC_SMBUS_BLOCK_DATA is disabled by default and must
246f16b75aSGuenter Roeck * be enabled explicitly by setting the I2C_FUNC_SMBUS_BLOCK_DATA bits
256f16b75aSGuenter Roeck * in the 'functionality' module parameter.
266f16b75aSGuenter Roeck */
276f16b75aSGuenter Roeck #define STUB_FUNC_DEFAULT \
286f16b75aSGuenter Roeck (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | \
2931d178bfSJean Delvare I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | \
3031d178bfSJean Delvare I2C_FUNC_SMBUS_I2C_BLOCK)
3131d178bfSJean Delvare
326f16b75aSGuenter Roeck #define STUB_FUNC_ALL \
336f16b75aSGuenter Roeck (STUB_FUNC_DEFAULT | I2C_FUNC_SMBUS_BLOCK_DATA)
346f16b75aSGuenter Roeck
3531d178bfSJean Delvare static unsigned short chip_addr[MAX_CHIPS];
3631d178bfSJean Delvare module_param_array(chip_addr, ushort, NULL, S_IRUGO);
3731d178bfSJean Delvare MODULE_PARM_DESC(chip_addr,
3831d178bfSJean Delvare "Chip addresses (up to 10, between 0x03 and 0x77)");
3931d178bfSJean Delvare
406f16b75aSGuenter Roeck static unsigned long functionality = STUB_FUNC_DEFAULT;
4131d178bfSJean Delvare module_param(functionality, ulong, S_IRUGO | S_IWUSR);
4231d178bfSJean Delvare MODULE_PARM_DESC(functionality, "Override functionality bitfield");
4331d178bfSJean Delvare
442408c17fSJean Delvare /* Some chips have banked register ranges */
452408c17fSJean Delvare
462408c17fSJean Delvare static u8 bank_reg[MAX_CHIPS];
472408c17fSJean Delvare module_param_array(bank_reg, byte, NULL, S_IRUGO);
482408c17fSJean Delvare MODULE_PARM_DESC(bank_reg, "Bank register");
492408c17fSJean Delvare
502408c17fSJean Delvare static u8 bank_mask[MAX_CHIPS];
512408c17fSJean Delvare module_param_array(bank_mask, byte, NULL, S_IRUGO);
522408c17fSJean Delvare MODULE_PARM_DESC(bank_mask, "Bank value mask");
532408c17fSJean Delvare
542408c17fSJean Delvare static u8 bank_start[MAX_CHIPS];
552408c17fSJean Delvare module_param_array(bank_start, byte, NULL, S_IRUGO);
562408c17fSJean Delvare MODULE_PARM_DESC(bank_start, "First banked register");
572408c17fSJean Delvare
582408c17fSJean Delvare static u8 bank_end[MAX_CHIPS];
592408c17fSJean Delvare module_param_array(bank_end, byte, NULL, S_IRUGO);
602408c17fSJean Delvare MODULE_PARM_DESC(bank_end, "Last banked register");
612408c17fSJean Delvare
626f16b75aSGuenter Roeck struct smbus_block_data {
636f16b75aSGuenter Roeck struct list_head node;
646f16b75aSGuenter Roeck u8 command;
656f16b75aSGuenter Roeck u8 len;
666f16b75aSGuenter Roeck u8 block[I2C_SMBUS_BLOCK_MAX];
676f16b75aSGuenter Roeck };
686f16b75aSGuenter Roeck
6931d178bfSJean Delvare struct stub_chip {
7031d178bfSJean Delvare u8 pointer;
7131d178bfSJean Delvare u16 words[256]; /* Byte operations use the LSB as per SMBus
7231d178bfSJean Delvare specification */
736f16b75aSGuenter Roeck struct list_head smbus_blocks;
742408c17fSJean Delvare
752408c17fSJean Delvare /* For chips with banks, extra registers are allocated dynamically */
762408c17fSJean Delvare u8 bank_reg;
772408c17fSJean Delvare u8 bank_shift;
782408c17fSJean Delvare u8 bank_mask;
792408c17fSJean Delvare u8 bank_sel; /* Currently selected bank */
802408c17fSJean Delvare u8 bank_start;
812408c17fSJean Delvare u8 bank_end;
822408c17fSJean Delvare u16 bank_size;
832408c17fSJean Delvare u16 *bank_words; /* Room for bank_mask * bank_size registers */
8431d178bfSJean Delvare };
8531d178bfSJean Delvare
8631d178bfSJean Delvare static struct stub_chip *stub_chips;
871dff5983SJean Delvare static int stub_chips_nr;
8831d178bfSJean Delvare
stub_find_block(struct device * dev,struct stub_chip * chip,u8 command,bool create)896f16b75aSGuenter Roeck static struct smbus_block_data *stub_find_block(struct device *dev,
906f16b75aSGuenter Roeck struct stub_chip *chip,
916f16b75aSGuenter Roeck u8 command, bool create)
926f16b75aSGuenter Roeck {
936f16b75aSGuenter Roeck struct smbus_block_data *b, *rb = NULL;
946f16b75aSGuenter Roeck
956f16b75aSGuenter Roeck list_for_each_entry(b, &chip->smbus_blocks, node) {
966f16b75aSGuenter Roeck if (b->command == command) {
976f16b75aSGuenter Roeck rb = b;
986f16b75aSGuenter Roeck break;
996f16b75aSGuenter Roeck }
1006f16b75aSGuenter Roeck }
1016f16b75aSGuenter Roeck if (rb == NULL && create) {
1026f16b75aSGuenter Roeck rb = devm_kzalloc(dev, sizeof(*rb), GFP_KERNEL);
1036f16b75aSGuenter Roeck if (rb == NULL)
1046f16b75aSGuenter Roeck return rb;
1056f16b75aSGuenter Roeck rb->command = command;
1066f16b75aSGuenter Roeck list_add(&rb->node, &chip->smbus_blocks);
1076f16b75aSGuenter Roeck }
1086f16b75aSGuenter Roeck return rb;
1096f16b75aSGuenter Roeck }
1106f16b75aSGuenter Roeck
stub_get_wordp(struct stub_chip * chip,u8 offset)1112408c17fSJean Delvare static u16 *stub_get_wordp(struct stub_chip *chip, u8 offset)
1122408c17fSJean Delvare {
1132408c17fSJean Delvare if (chip->bank_sel &&
1142408c17fSJean Delvare offset >= chip->bank_start && offset <= chip->bank_end)
1152408c17fSJean Delvare return chip->bank_words +
1162408c17fSJean Delvare (chip->bank_sel - 1) * chip->bank_size +
1172408c17fSJean Delvare offset - chip->bank_start;
1182408c17fSJean Delvare else
1192408c17fSJean Delvare return chip->words + offset;
1202408c17fSJean Delvare }
1212408c17fSJean Delvare
12231d178bfSJean Delvare /* Return negative errno on error. */
stub_xfer(struct i2c_adapter * adap,u16 addr,unsigned short flags,char read_write,u8 command,int size,union i2c_smbus_data * data)12331d178bfSJean Delvare static s32 stub_xfer(struct i2c_adapter *adap, u16 addr, unsigned short flags,
12431d178bfSJean Delvare char read_write, u8 command, int size, union i2c_smbus_data *data)
12531d178bfSJean Delvare {
12631d178bfSJean Delvare s32 ret;
12731d178bfSJean Delvare int i, len;
12831d178bfSJean Delvare struct stub_chip *chip = NULL;
1296f16b75aSGuenter Roeck struct smbus_block_data *b;
1302408c17fSJean Delvare u16 *wordp;
13131d178bfSJean Delvare
13231d178bfSJean Delvare /* Search for the right chip */
1331dff5983SJean Delvare for (i = 0; i < stub_chips_nr; i++) {
13431d178bfSJean Delvare if (addr == chip_addr[i]) {
13531d178bfSJean Delvare chip = stub_chips + i;
13631d178bfSJean Delvare break;
13731d178bfSJean Delvare }
13831d178bfSJean Delvare }
13931d178bfSJean Delvare if (!chip)
14031d178bfSJean Delvare return -ENODEV;
14131d178bfSJean Delvare
14231d178bfSJean Delvare switch (size) {
14331d178bfSJean Delvare
14431d178bfSJean Delvare case I2C_SMBUS_QUICK:
14531d178bfSJean Delvare dev_dbg(&adap->dev, "smbus quick - addr 0x%02x\n", addr);
14631d178bfSJean Delvare ret = 0;
14731d178bfSJean Delvare break;
14831d178bfSJean Delvare
14931d178bfSJean Delvare case I2C_SMBUS_BYTE:
15031d178bfSJean Delvare if (read_write == I2C_SMBUS_WRITE) {
15131d178bfSJean Delvare chip->pointer = command;
15231d178bfSJean Delvare dev_dbg(&adap->dev,
15331d178bfSJean Delvare "smbus byte - addr 0x%02x, wrote 0x%02x.\n",
15431d178bfSJean Delvare addr, command);
15531d178bfSJean Delvare } else {
1562408c17fSJean Delvare wordp = stub_get_wordp(chip, chip->pointer++);
1572408c17fSJean Delvare data->byte = *wordp & 0xff;
15831d178bfSJean Delvare dev_dbg(&adap->dev,
15931d178bfSJean Delvare "smbus byte - addr 0x%02x, read 0x%02x.\n",
16031d178bfSJean Delvare addr, data->byte);
16131d178bfSJean Delvare }
16231d178bfSJean Delvare
16331d178bfSJean Delvare ret = 0;
16431d178bfSJean Delvare break;
16531d178bfSJean Delvare
16631d178bfSJean Delvare case I2C_SMBUS_BYTE_DATA:
1672408c17fSJean Delvare wordp = stub_get_wordp(chip, command);
16831d178bfSJean Delvare if (read_write == I2C_SMBUS_WRITE) {
1692408c17fSJean Delvare *wordp &= 0xff00;
1702408c17fSJean Delvare *wordp |= data->byte;
17131d178bfSJean Delvare dev_dbg(&adap->dev,
17231d178bfSJean Delvare "smbus byte data - addr 0x%02x, wrote 0x%02x at 0x%02x.\n",
17331d178bfSJean Delvare addr, data->byte, command);
1742408c17fSJean Delvare
1752408c17fSJean Delvare /* Set the bank as needed */
1762408c17fSJean Delvare if (chip->bank_words && command == chip->bank_reg) {
1772408c17fSJean Delvare chip->bank_sel =
1782408c17fSJean Delvare (data->byte >> chip->bank_shift)
1792408c17fSJean Delvare & chip->bank_mask;
1802408c17fSJean Delvare dev_dbg(&adap->dev,
1812408c17fSJean Delvare "switching to bank %u.\n",
1822408c17fSJean Delvare chip->bank_sel);
1832408c17fSJean Delvare }
18431d178bfSJean Delvare } else {
1852408c17fSJean Delvare data->byte = *wordp & 0xff;
18631d178bfSJean Delvare dev_dbg(&adap->dev,
18731d178bfSJean Delvare "smbus byte data - addr 0x%02x, read 0x%02x at 0x%02x.\n",
18831d178bfSJean Delvare addr, data->byte, command);
18931d178bfSJean Delvare }
19031d178bfSJean Delvare chip->pointer = command + 1;
19131d178bfSJean Delvare
19231d178bfSJean Delvare ret = 0;
19331d178bfSJean Delvare break;
19431d178bfSJean Delvare
19531d178bfSJean Delvare case I2C_SMBUS_WORD_DATA:
1962408c17fSJean Delvare wordp = stub_get_wordp(chip, command);
19731d178bfSJean Delvare if (read_write == I2C_SMBUS_WRITE) {
1982408c17fSJean Delvare *wordp = data->word;
19931d178bfSJean Delvare dev_dbg(&adap->dev,
20031d178bfSJean Delvare "smbus word data - addr 0x%02x, wrote 0x%04x at 0x%02x.\n",
20131d178bfSJean Delvare addr, data->word, command);
20231d178bfSJean Delvare } else {
2032408c17fSJean Delvare data->word = *wordp;
20431d178bfSJean Delvare dev_dbg(&adap->dev,
20531d178bfSJean Delvare "smbus word data - addr 0x%02x, read 0x%04x at 0x%02x.\n",
20631d178bfSJean Delvare addr, data->word, command);
20731d178bfSJean Delvare }
20831d178bfSJean Delvare
20931d178bfSJean Delvare ret = 0;
21031d178bfSJean Delvare break;
21131d178bfSJean Delvare
21231d178bfSJean Delvare case I2C_SMBUS_I2C_BLOCK_DATA:
2132408c17fSJean Delvare /*
2142408c17fSJean Delvare * We ignore banks here, because banked chips don't use I2C
2152408c17fSJean Delvare * block transfers
2162408c17fSJean Delvare */
2170f6ba0d1SJean Delvare if (data->block[0] > 256 - command) /* Avoid overrun */
2180f6ba0d1SJean Delvare data->block[0] = 256 - command;
21931d178bfSJean Delvare len = data->block[0];
22031d178bfSJean Delvare if (read_write == I2C_SMBUS_WRITE) {
22131d178bfSJean Delvare for (i = 0; i < len; i++) {
22231d178bfSJean Delvare chip->words[command + i] &= 0xff00;
22331d178bfSJean Delvare chip->words[command + i] |= data->block[1 + i];
22431d178bfSJean Delvare }
22531d178bfSJean Delvare dev_dbg(&adap->dev,
22631d178bfSJean Delvare "i2c block data - addr 0x%02x, wrote %d bytes at 0x%02x.\n",
22731d178bfSJean Delvare addr, len, command);
22831d178bfSJean Delvare } else {
22931d178bfSJean Delvare for (i = 0; i < len; i++) {
23031d178bfSJean Delvare data->block[1 + i] =
23131d178bfSJean Delvare chip->words[command + i] & 0xff;
23231d178bfSJean Delvare }
23331d178bfSJean Delvare dev_dbg(&adap->dev,
23431d178bfSJean Delvare "i2c block data - addr 0x%02x, read %d bytes at 0x%02x.\n",
23531d178bfSJean Delvare addr, len, command);
23631d178bfSJean Delvare }
23731d178bfSJean Delvare
23831d178bfSJean Delvare ret = 0;
23931d178bfSJean Delvare break;
24031d178bfSJean Delvare
2416f16b75aSGuenter Roeck case I2C_SMBUS_BLOCK_DATA:
2422408c17fSJean Delvare /*
2432408c17fSJean Delvare * We ignore banks here, because chips typically don't use both
2442408c17fSJean Delvare * banks and SMBus block transfers
2452408c17fSJean Delvare */
2466f16b75aSGuenter Roeck b = stub_find_block(&adap->dev, chip, command, false);
2476f16b75aSGuenter Roeck if (read_write == I2C_SMBUS_WRITE) {
2486f16b75aSGuenter Roeck len = data->block[0];
2496f16b75aSGuenter Roeck if (len == 0 || len > I2C_SMBUS_BLOCK_MAX) {
2506f16b75aSGuenter Roeck ret = -EINVAL;
2516f16b75aSGuenter Roeck break;
2526f16b75aSGuenter Roeck }
2536f16b75aSGuenter Roeck if (b == NULL) {
2546f16b75aSGuenter Roeck b = stub_find_block(&adap->dev, chip, command,
2556f16b75aSGuenter Roeck true);
2566f16b75aSGuenter Roeck if (b == NULL) {
2576f16b75aSGuenter Roeck ret = -ENOMEM;
2586f16b75aSGuenter Roeck break;
2596f16b75aSGuenter Roeck }
2606f16b75aSGuenter Roeck }
2616f16b75aSGuenter Roeck /* Largest write sets read block length */
2626f16b75aSGuenter Roeck if (len > b->len)
2636f16b75aSGuenter Roeck b->len = len;
2646f16b75aSGuenter Roeck for (i = 0; i < len; i++)
2656f16b75aSGuenter Roeck b->block[i] = data->block[i + 1];
2666f16b75aSGuenter Roeck /* update for byte and word commands */
2676f16b75aSGuenter Roeck chip->words[command] = (b->block[0] << 8) | b->len;
2686f16b75aSGuenter Roeck dev_dbg(&adap->dev,
2696f16b75aSGuenter Roeck "smbus block data - addr 0x%02x, wrote %d bytes at 0x%02x.\n",
2706f16b75aSGuenter Roeck addr, len, command);
2716f16b75aSGuenter Roeck } else {
2726f16b75aSGuenter Roeck if (b == NULL) {
2736f16b75aSGuenter Roeck dev_dbg(&adap->dev,
2746f16b75aSGuenter Roeck "SMBus block read command without prior block write not supported\n");
2756f16b75aSGuenter Roeck ret = -EOPNOTSUPP;
2766f16b75aSGuenter Roeck break;
2776f16b75aSGuenter Roeck }
2786f16b75aSGuenter Roeck len = b->len;
2796f16b75aSGuenter Roeck data->block[0] = len;
2806f16b75aSGuenter Roeck for (i = 0; i < len; i++)
2816f16b75aSGuenter Roeck data->block[i + 1] = b->block[i];
2826f16b75aSGuenter Roeck dev_dbg(&adap->dev,
2836f16b75aSGuenter Roeck "smbus block data - addr 0x%02x, read %d bytes at 0x%02x.\n",
2846f16b75aSGuenter Roeck addr, len, command);
2856f16b75aSGuenter Roeck }
2866f16b75aSGuenter Roeck
2876f16b75aSGuenter Roeck ret = 0;
2886f16b75aSGuenter Roeck break;
2896f16b75aSGuenter Roeck
29031d178bfSJean Delvare default:
29131d178bfSJean Delvare dev_dbg(&adap->dev, "Unsupported I2C/SMBus command\n");
29231d178bfSJean Delvare ret = -EOPNOTSUPP;
29331d178bfSJean Delvare break;
29431d178bfSJean Delvare } /* switch (size) */
29531d178bfSJean Delvare
29631d178bfSJean Delvare return ret;
29731d178bfSJean Delvare }
29831d178bfSJean Delvare
stub_func(struct i2c_adapter * adapter)29931d178bfSJean Delvare static u32 stub_func(struct i2c_adapter *adapter)
30031d178bfSJean Delvare {
3016f16b75aSGuenter Roeck return STUB_FUNC_ALL & functionality;
30231d178bfSJean Delvare }
30331d178bfSJean Delvare
30431d178bfSJean Delvare static const struct i2c_algorithm smbus_algorithm = {
30531d178bfSJean Delvare .functionality = stub_func,
30631d178bfSJean Delvare .smbus_xfer = stub_xfer,
30731d178bfSJean Delvare };
30831d178bfSJean Delvare
30931d178bfSJean Delvare static struct i2c_adapter stub_adapter = {
31031d178bfSJean Delvare .owner = THIS_MODULE,
31131d178bfSJean Delvare .class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
31231d178bfSJean Delvare .algo = &smbus_algorithm,
31331d178bfSJean Delvare .name = "SMBus stub driver",
31431d178bfSJean Delvare };
31531d178bfSJean Delvare
i2c_stub_allocate_banks(int i)3162408c17fSJean Delvare static int __init i2c_stub_allocate_banks(int i)
3172408c17fSJean Delvare {
3182408c17fSJean Delvare struct stub_chip *chip = stub_chips + i;
3192408c17fSJean Delvare
3202408c17fSJean Delvare chip->bank_reg = bank_reg[i];
3212408c17fSJean Delvare chip->bank_start = bank_start[i];
3222408c17fSJean Delvare chip->bank_end = bank_end[i];
3232408c17fSJean Delvare chip->bank_size = bank_end[i] - bank_start[i] + 1;
3242408c17fSJean Delvare
3252408c17fSJean Delvare /* We assume that all bits in the mask are contiguous */
3262408c17fSJean Delvare chip->bank_mask = bank_mask[i];
3272408c17fSJean Delvare while (!(chip->bank_mask & 1)) {
3282408c17fSJean Delvare chip->bank_shift++;
3292408c17fSJean Delvare chip->bank_mask >>= 1;
3302408c17fSJean Delvare }
3312408c17fSJean Delvare
3326396bb22SKees Cook chip->bank_words = kcalloc(chip->bank_mask * chip->bank_size,
3336396bb22SKees Cook sizeof(u16),
3346396bb22SKees Cook GFP_KERNEL);
3352408c17fSJean Delvare if (!chip->bank_words)
3362408c17fSJean Delvare return -ENOMEM;
3372408c17fSJean Delvare
3386c427787SWolfram Sang pr_debug("Allocated %u banks of %u words each (registers 0x%02x to 0x%02x)\n",
3392408c17fSJean Delvare chip->bank_mask, chip->bank_size, chip->bank_start,
3402408c17fSJean Delvare chip->bank_end);
3412408c17fSJean Delvare
3422408c17fSJean Delvare return 0;
3432408c17fSJean Delvare }
3442408c17fSJean Delvare
i2c_stub_free(void)3452408c17fSJean Delvare static void i2c_stub_free(void)
3462408c17fSJean Delvare {
3472408c17fSJean Delvare int i;
3482408c17fSJean Delvare
3492408c17fSJean Delvare for (i = 0; i < stub_chips_nr; i++)
3502408c17fSJean Delvare kfree(stub_chips[i].bank_words);
3512408c17fSJean Delvare kfree(stub_chips);
3522408c17fSJean Delvare }
3532408c17fSJean Delvare
i2c_stub_init(void)35431d178bfSJean Delvare static int __init i2c_stub_init(void)
35531d178bfSJean Delvare {
35631d178bfSJean Delvare int i, ret;
35731d178bfSJean Delvare
35831d178bfSJean Delvare if (!chip_addr[0]) {
3596c427787SWolfram Sang pr_err("Please specify a chip address\n");
36031d178bfSJean Delvare return -ENODEV;
36131d178bfSJean Delvare }
36231d178bfSJean Delvare
36331d178bfSJean Delvare for (i = 0; i < MAX_CHIPS && chip_addr[i]; i++) {
36431d178bfSJean Delvare if (chip_addr[i] < 0x03 || chip_addr[i] > 0x77) {
3656c427787SWolfram Sang pr_err("Invalid chip address 0x%02x\n",
36631d178bfSJean Delvare chip_addr[i]);
36731d178bfSJean Delvare return -EINVAL;
36831d178bfSJean Delvare }
36931d178bfSJean Delvare
3706c427787SWolfram Sang pr_info("Virtual chip at 0x%02x\n", chip_addr[i]);
37131d178bfSJean Delvare }
37231d178bfSJean Delvare
37331d178bfSJean Delvare /* Allocate memory for all chips at once */
3741dff5983SJean Delvare stub_chips_nr = i;
3751dff5983SJean Delvare stub_chips = kcalloc(stub_chips_nr, sizeof(struct stub_chip),
3761dff5983SJean Delvare GFP_KERNEL);
3776c427787SWolfram Sang if (!stub_chips)
37831d178bfSJean Delvare return -ENOMEM;
3796c427787SWolfram Sang
3802408c17fSJean Delvare for (i = 0; i < stub_chips_nr; i++) {
3816f16b75aSGuenter Roeck INIT_LIST_HEAD(&stub_chips[i].smbus_blocks);
38231d178bfSJean Delvare
3832408c17fSJean Delvare /* Allocate extra memory for banked register ranges */
3842408c17fSJean Delvare if (bank_mask[i]) {
3852408c17fSJean Delvare ret = i2c_stub_allocate_banks(i);
3862408c17fSJean Delvare if (ret)
3872408c17fSJean Delvare goto fail_free;
3882408c17fSJean Delvare }
3892408c17fSJean Delvare }
3902408c17fSJean Delvare
39131d178bfSJean Delvare ret = i2c_add_adapter(&stub_adapter);
39231d178bfSJean Delvare if (ret)
3932408c17fSJean Delvare goto fail_free;
3942408c17fSJean Delvare
3952408c17fSJean Delvare return 0;
3962408c17fSJean Delvare
3972408c17fSJean Delvare fail_free:
3982408c17fSJean Delvare i2c_stub_free();
39931d178bfSJean Delvare return ret;
40031d178bfSJean Delvare }
40131d178bfSJean Delvare
i2c_stub_exit(void)40231d178bfSJean Delvare static void __exit i2c_stub_exit(void)
40331d178bfSJean Delvare {
40431d178bfSJean Delvare i2c_del_adapter(&stub_adapter);
4052408c17fSJean Delvare i2c_stub_free();
40631d178bfSJean Delvare }
40731d178bfSJean Delvare
40831d178bfSJean Delvare MODULE_AUTHOR("Mark M. Hoffman <mhoffman@lightlink.com>");
40931d178bfSJean Delvare MODULE_DESCRIPTION("I2C stub driver");
41031d178bfSJean Delvare MODULE_LICENSE("GPL");
41131d178bfSJean Delvare
41231d178bfSJean Delvare module_init(i2c_stub_init);
41331d178bfSJean Delvare module_exit(i2c_stub_exit);
414