aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/i2c/i2c-stub.c
diff options
context:
space:
mode:
authorGuenter Roeck <linux@roeck-us.net>2014-07-17 12:56:03 -0400
committerWolfram Sang <wsa@the-dreams.de>2014-07-17 13:11:35 -0400
commit6f16b75a41abbbd11c4c8b7c62eb66604879b981 (patch)
tree6183b1ff9454533e8c4bd14809749052eb1fea3c /drivers/i2c/i2c-stub.c
parent281ec367bff42304e0dc5cbc8d267ce9251478b7 (diff)
i2c: stub: Add support for SMBus block commands
SMBus block commands are different to I2C block commands since the returned data is not normally accessible with byte or word commands on other command offsets. Add linked list of 'block' commands to support those commands. Access mechanism is quite simple: Block commands must be written before they can be read. Subsequent writes can be partial. Block read commands always return the number of bytes associated with the longest previous write. Signed-off-by: Guenter Roeck <linux@roeck-us.net> Reviewed-by: Jean Delvare <jdelvare@suse.de> Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
Diffstat (limited to 'drivers/i2c/i2c-stub.c')
-rw-r--r--drivers/i2c/i2c-stub.c99
1 files changed, 94 insertions, 5 deletions
diff --git a/drivers/i2c/i2c-stub.c b/drivers/i2c/i2c-stub.c
index 77e4849d2f2a..e0bb4655661d 100644
--- a/drivers/i2c/i2c-stub.c
+++ b/drivers/i2c/i2c-stub.c
@@ -27,29 +27,70 @@
27#include <linux/slab.h> 27#include <linux/slab.h>
28#include <linux/errno.h> 28#include <linux/errno.h>
29#include <linux/i2c.h> 29#include <linux/i2c.h>
30#include <linux/list.h>
30 31
31#define MAX_CHIPS 10 32#define MAX_CHIPS 10
32#define STUB_FUNC (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | \ 33
33 I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | \ 34/*
34 I2C_FUNC_SMBUS_I2C_BLOCK) 35 * Support for I2C_FUNC_SMBUS_BLOCK_DATA is disabled by default and must
36 * be enabled explicitly by setting the I2C_FUNC_SMBUS_BLOCK_DATA bits
37 * in the 'functionality' module parameter.
38 */
39#define STUB_FUNC_DEFAULT \
40 (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | \
41 I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | \
42 I2C_FUNC_SMBUS_I2C_BLOCK)
43
44#define STUB_FUNC_ALL \
45 (STUB_FUNC_DEFAULT | I2C_FUNC_SMBUS_BLOCK_DATA)
35 46
36static unsigned short chip_addr[MAX_CHIPS]; 47static unsigned short chip_addr[MAX_CHIPS];
37module_param_array(chip_addr, ushort, NULL, S_IRUGO); 48module_param_array(chip_addr, ushort, NULL, S_IRUGO);
38MODULE_PARM_DESC(chip_addr, 49MODULE_PARM_DESC(chip_addr,
39 "Chip addresses (up to 10, between 0x03 and 0x77)"); 50 "Chip addresses (up to 10, between 0x03 and 0x77)");
40 51
41static unsigned long functionality = STUB_FUNC; 52static unsigned long functionality = STUB_FUNC_DEFAULT;
42module_param(functionality, ulong, S_IRUGO | S_IWUSR); 53module_param(functionality, ulong, S_IRUGO | S_IWUSR);
43MODULE_PARM_DESC(functionality, "Override functionality bitfield"); 54MODULE_PARM_DESC(functionality, "Override functionality bitfield");
44 55
56struct smbus_block_data {
57 struct list_head node;
58 u8 command;
59 u8 len;
60 u8 block[I2C_SMBUS_BLOCK_MAX];
61};
62
45struct stub_chip { 63struct stub_chip {
46 u8 pointer; 64 u8 pointer;
47 u16 words[256]; /* Byte operations use the LSB as per SMBus 65 u16 words[256]; /* Byte operations use the LSB as per SMBus
48 specification */ 66 specification */
67 struct list_head smbus_blocks;
49}; 68};
50 69
51static struct stub_chip *stub_chips; 70static struct stub_chip *stub_chips;
52 71
72static struct smbus_block_data *stub_find_block(struct device *dev,
73 struct stub_chip *chip,
74 u8 command, bool create)
75{
76 struct smbus_block_data *b, *rb = NULL;
77
78 list_for_each_entry(b, &chip->smbus_blocks, node) {
79 if (b->command == command) {
80 rb = b;
81 break;
82 }
83 }
84 if (rb == NULL && create) {
85 rb = devm_kzalloc(dev, sizeof(*rb), GFP_KERNEL);
86 if (rb == NULL)
87 return rb;
88 rb->command = command;
89 list_add(&rb->node, &chip->smbus_blocks);
90 }
91 return rb;
92}
93
53/* Return negative errno on error. */ 94/* Return negative errno on error. */
54static s32 stub_xfer(struct i2c_adapter *adap, u16 addr, unsigned short flags, 95static s32 stub_xfer(struct i2c_adapter *adap, u16 addr, unsigned short flags,
55 char read_write, u8 command, int size, union i2c_smbus_data *data) 96 char read_write, u8 command, int size, union i2c_smbus_data *data)
@@ -57,6 +98,7 @@ static s32 stub_xfer(struct i2c_adapter *adap, u16 addr, unsigned short flags,
57 s32 ret; 98 s32 ret;
58 int i, len; 99 int i, len;
59 struct stub_chip *chip = NULL; 100 struct stub_chip *chip = NULL;
101 struct smbus_block_data *b;
60 102
61 /* Search for the right chip */ 103 /* Search for the right chip */
62 for (i = 0; i < MAX_CHIPS && chip_addr[i]; i++) { 104 for (i = 0; i < MAX_CHIPS && chip_addr[i]; i++) {
@@ -148,6 +190,51 @@ static s32 stub_xfer(struct i2c_adapter *adap, u16 addr, unsigned short flags,
148 ret = 0; 190 ret = 0;
149 break; 191 break;
150 192
193 case I2C_SMBUS_BLOCK_DATA:
194 b = stub_find_block(&adap->dev, chip, command, false);
195 if (read_write == I2C_SMBUS_WRITE) {
196 len = data->block[0];
197 if (len == 0 || len > I2C_SMBUS_BLOCK_MAX) {
198 ret = -EINVAL;
199 break;
200 }
201 if (b == NULL) {
202 b = stub_find_block(&adap->dev, chip, command,
203 true);
204 if (b == NULL) {
205 ret = -ENOMEM;
206 break;
207 }
208 }
209 /* Largest write sets read block length */
210 if (len > b->len)
211 b->len = len;
212 for (i = 0; i < len; i++)
213 b->block[i] = data->block[i + 1];
214 /* update for byte and word commands */
215 chip->words[command] = (b->block[0] << 8) | b->len;
216 dev_dbg(&adap->dev,
217 "smbus block data - addr 0x%02x, wrote %d bytes at 0x%02x.\n",
218 addr, len, command);
219 } else {
220 if (b == NULL) {
221 dev_dbg(&adap->dev,
222 "SMBus block read command without prior block write not supported\n");
223 ret = -EOPNOTSUPP;
224 break;
225 }
226 len = b->len;
227 data->block[0] = len;
228 for (i = 0; i < len; i++)
229 data->block[i + 1] = b->block[i];
230 dev_dbg(&adap->dev,
231 "smbus block data - addr 0x%02x, read %d bytes at 0x%02x.\n",
232 addr, len, command);
233 }
234
235 ret = 0;
236 break;
237
151 default: 238 default:
152 dev_dbg(&adap->dev, "Unsupported I2C/SMBus command\n"); 239 dev_dbg(&adap->dev, "Unsupported I2C/SMBus command\n");
153 ret = -EOPNOTSUPP; 240 ret = -EOPNOTSUPP;
@@ -159,7 +246,7 @@ static s32 stub_xfer(struct i2c_adapter *adap, u16 addr, unsigned short flags,
159 246
160static u32 stub_func(struct i2c_adapter *adapter) 247static u32 stub_func(struct i2c_adapter *adapter)
161{ 248{
162 return STUB_FUNC & functionality; 249 return STUB_FUNC_ALL & functionality;
163} 250}
164 251
165static const struct i2c_algorithm smbus_algorithm = { 252static const struct i2c_algorithm smbus_algorithm = {
@@ -199,6 +286,8 @@ static int __init i2c_stub_init(void)
199 pr_err("i2c-stub: Out of memory\n"); 286 pr_err("i2c-stub: Out of memory\n");
200 return -ENOMEM; 287 return -ENOMEM;
201 } 288 }
289 for (i--; i >= 0; i--)
290 INIT_LIST_HEAD(&stub_chips[i].smbus_blocks);
202 291
203 ret = i2c_add_adapter(&stub_adapter); 292 ret = i2c_add_adapter(&stub_adapter);
204 if (ret) 293 if (ret)