diff options
| -rw-r--r-- | drivers/base/regmap/regmap-i2c.c | 104 | ||||
| -rw-r--r-- | drivers/base/regmap/regmap.c | 26 | ||||
| -rw-r--r-- | include/linux/regmap.h | 6 |
3 files changed, 134 insertions, 2 deletions
diff --git a/drivers/base/regmap/regmap-i2c.c b/drivers/base/regmap/regmap-i2c.c index ebd189529760..ca193d1ef47c 100644 --- a/drivers/base/regmap/regmap-i2c.c +++ b/drivers/base/regmap/regmap-i2c.c | |||
| @@ -14,6 +14,79 @@ | |||
| 14 | #include <linux/i2c.h> | 14 | #include <linux/i2c.h> |
| 15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
| 16 | 16 | ||
| 17 | |||
| 18 | static int regmap_smbus_byte_reg_read(void *context, unsigned int reg, | ||
| 19 | unsigned int *val) | ||
| 20 | { | ||
| 21 | struct device *dev = context; | ||
| 22 | struct i2c_client *i2c = to_i2c_client(dev); | ||
| 23 | int ret; | ||
| 24 | |||
| 25 | if (reg > 0xff) | ||
| 26 | return -EINVAL; | ||
| 27 | |||
| 28 | ret = i2c_smbus_read_byte_data(i2c, reg); | ||
| 29 | if (ret < 0) | ||
| 30 | return ret; | ||
| 31 | |||
| 32 | *val = ret; | ||
| 33 | |||
| 34 | return 0; | ||
| 35 | } | ||
| 36 | |||
| 37 | static int regmap_smbus_byte_reg_write(void *context, unsigned int reg, | ||
| 38 | unsigned int val) | ||
| 39 | { | ||
| 40 | struct device *dev = context; | ||
| 41 | struct i2c_client *i2c = to_i2c_client(dev); | ||
| 42 | |||
| 43 | if (val > 0xff || reg > 0xff) | ||
| 44 | return -EINVAL; | ||
| 45 | |||
| 46 | return i2c_smbus_write_byte_data(i2c, reg, val); | ||
| 47 | } | ||
| 48 | |||
| 49 | static struct regmap_bus regmap_smbus_byte = { | ||
| 50 | .reg_write = regmap_smbus_byte_reg_write, | ||
| 51 | .reg_read = regmap_smbus_byte_reg_read, | ||
| 52 | }; | ||
| 53 | |||
| 54 | static int regmap_smbus_word_reg_read(void *context, unsigned int reg, | ||
| 55 | unsigned int *val) | ||
| 56 | { | ||
| 57 | struct device *dev = context; | ||
| 58 | struct i2c_client *i2c = to_i2c_client(dev); | ||
| 59 | int ret; | ||
| 60 | |||
| 61 | if (reg > 0xff) | ||
| 62 | return -EINVAL; | ||
| 63 | |||
| 64 | ret = i2c_smbus_read_word_data(i2c, reg); | ||
| 65 | if (ret < 0) | ||
| 66 | return ret; | ||
| 67 | |||
| 68 | *val = ret; | ||
| 69 | |||
| 70 | return 0; | ||
| 71 | } | ||
| 72 | |||
| 73 | static int regmap_smbus_word_reg_write(void *context, unsigned int reg, | ||
| 74 | unsigned int val) | ||
| 75 | { | ||
| 76 | struct device *dev = context; | ||
| 77 | struct i2c_client *i2c = to_i2c_client(dev); | ||
| 78 | |||
| 79 | if (val > 0xffff || reg > 0xff) | ||
| 80 | return -EINVAL; | ||
| 81 | |||
| 82 | return i2c_smbus_write_word_data(i2c, reg, val); | ||
| 83 | } | ||
| 84 | |||
| 85 | static struct regmap_bus regmap_smbus_word = { | ||
| 86 | .reg_write = regmap_smbus_word_reg_write, | ||
| 87 | .reg_read = regmap_smbus_word_reg_read, | ||
| 88 | }; | ||
| 89 | |||
| 17 | static int regmap_i2c_write(void *context, const void *data, size_t count) | 90 | static int regmap_i2c_write(void *context, const void *data, size_t count) |
| 18 | { | 91 | { |
| 19 | struct device *dev = context; | 92 | struct device *dev = context; |
| @@ -97,6 +170,23 @@ static struct regmap_bus regmap_i2c = { | |||
| 97 | .read = regmap_i2c_read, | 170 | .read = regmap_i2c_read, |
| 98 | }; | 171 | }; |
| 99 | 172 | ||
| 173 | static const struct regmap_bus *regmap_get_i2c_bus(struct i2c_client *i2c, | ||
| 174 | const struct regmap_config *config) | ||
| 175 | { | ||
| 176 | if (i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C)) | ||
| 177 | return ®map_i2c; | ||
| 178 | else if (config->val_bits == 16 && config->reg_bits == 8 && | ||
| 179 | i2c_check_functionality(i2c->adapter, | ||
| 180 | I2C_FUNC_SMBUS_WORD_DATA)) | ||
| 181 | return ®map_smbus_word; | ||
| 182 | else if (config->val_bits == 8 && config->reg_bits == 8 && | ||
| 183 | i2c_check_functionality(i2c->adapter, | ||
| 184 | I2C_FUNC_SMBUS_BYTE_DATA)) | ||
| 185 | return ®map_smbus_byte; | ||
| 186 | |||
| 187 | return ERR_PTR(-ENOTSUPP); | ||
| 188 | } | ||
| 189 | |||
| 100 | /** | 190 | /** |
| 101 | * regmap_init_i2c(): Initialise register map | 191 | * regmap_init_i2c(): Initialise register map |
| 102 | * | 192 | * |
| @@ -109,7 +199,12 @@ static struct regmap_bus regmap_i2c = { | |||
| 109 | struct regmap *regmap_init_i2c(struct i2c_client *i2c, | 199 | struct regmap *regmap_init_i2c(struct i2c_client *i2c, |
| 110 | const struct regmap_config *config) | 200 | const struct regmap_config *config) |
| 111 | { | 201 | { |
| 112 | return regmap_init(&i2c->dev, ®map_i2c, &i2c->dev, config); | 202 | const struct regmap_bus *bus = regmap_get_i2c_bus(i2c, config); |
| 203 | |||
| 204 | if (IS_ERR(bus)) | ||
| 205 | return ERR_CAST(bus); | ||
| 206 | |||
| 207 | return regmap_init(&i2c->dev, bus, &i2c->dev, config); | ||
| 113 | } | 208 | } |
| 114 | EXPORT_SYMBOL_GPL(regmap_init_i2c); | 209 | EXPORT_SYMBOL_GPL(regmap_init_i2c); |
| 115 | 210 | ||
| @@ -126,7 +221,12 @@ EXPORT_SYMBOL_GPL(regmap_init_i2c); | |||
| 126 | struct regmap *devm_regmap_init_i2c(struct i2c_client *i2c, | 221 | struct regmap *devm_regmap_init_i2c(struct i2c_client *i2c, |
| 127 | const struct regmap_config *config) | 222 | const struct regmap_config *config) |
| 128 | { | 223 | { |
| 129 | return devm_regmap_init(&i2c->dev, ®map_i2c, &i2c->dev, config); | 224 | const struct regmap_bus *bus = regmap_get_i2c_bus(i2c, config); |
| 225 | |||
| 226 | if (IS_ERR(bus)) | ||
| 227 | return ERR_CAST(bus); | ||
| 228 | |||
| 229 | return devm_regmap_init(&i2c->dev, bus, &i2c->dev, config); | ||
| 130 | } | 230 | } |
| 131 | EXPORT_SYMBOL_GPL(devm_regmap_init_i2c); | 231 | EXPORT_SYMBOL_GPL(devm_regmap_init_i2c); |
| 132 | 232 | ||
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 2615cc180d35..74d8c0672cf6 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c | |||
| @@ -35,10 +35,14 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg, | |||
| 35 | unsigned int mask, unsigned int val, | 35 | unsigned int mask, unsigned int val, |
| 36 | bool *change); | 36 | bool *change); |
| 37 | 37 | ||
| 38 | static int _regmap_bus_reg_read(void *context, unsigned int reg, | ||
| 39 | unsigned int *val); | ||
| 38 | static int _regmap_bus_read(void *context, unsigned int reg, | 40 | static int _regmap_bus_read(void *context, unsigned int reg, |
| 39 | unsigned int *val); | 41 | unsigned int *val); |
| 40 | static int _regmap_bus_formatted_write(void *context, unsigned int reg, | 42 | static int _regmap_bus_formatted_write(void *context, unsigned int reg, |
| 41 | unsigned int val); | 43 | unsigned int val); |
| 44 | static int _regmap_bus_reg_write(void *context, unsigned int reg, | ||
| 45 | unsigned int val); | ||
| 42 | static int _regmap_bus_raw_write(void *context, unsigned int reg, | 46 | static int _regmap_bus_raw_write(void *context, unsigned int reg, |
| 43 | unsigned int val); | 47 | unsigned int val); |
| 44 | 48 | ||
| @@ -537,6 +541,12 @@ struct regmap *regmap_init(struct device *dev, | |||
| 537 | 541 | ||
| 538 | map->defer_caching = false; | 542 | map->defer_caching = false; |
| 539 | goto skip_format_initialization; | 543 | goto skip_format_initialization; |
| 544 | } else if (!bus->read || !bus->write) { | ||
| 545 | map->reg_read = _regmap_bus_reg_read; | ||
| 546 | map->reg_write = _regmap_bus_reg_write; | ||
| 547 | |||
| 548 | map->defer_caching = false; | ||
| 549 | goto skip_format_initialization; | ||
| 540 | } else { | 550 | } else { |
| 541 | map->reg_read = _regmap_bus_read; | 551 | map->reg_read = _regmap_bus_read; |
| 542 | } | 552 | } |
| @@ -1336,6 +1346,14 @@ static int _regmap_bus_formatted_write(void *context, unsigned int reg, | |||
| 1336 | return ret; | 1346 | return ret; |
| 1337 | } | 1347 | } |
| 1338 | 1348 | ||
| 1349 | static int _regmap_bus_reg_write(void *context, unsigned int reg, | ||
| 1350 | unsigned int val) | ||
| 1351 | { | ||
| 1352 | struct regmap *map = context; | ||
| 1353 | |||
| 1354 | return map->bus->reg_write(map->bus_context, reg, val); | ||
| 1355 | } | ||
| 1356 | |||
| 1339 | static int _regmap_bus_raw_write(void *context, unsigned int reg, | 1357 | static int _regmap_bus_raw_write(void *context, unsigned int reg, |
| 1340 | unsigned int val) | 1358 | unsigned int val) |
| 1341 | { | 1359 | { |
| @@ -1980,6 +1998,14 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val, | |||
| 1980 | return ret; | 1998 | return ret; |
| 1981 | } | 1999 | } |
| 1982 | 2000 | ||
| 2001 | static int _regmap_bus_reg_read(void *context, unsigned int reg, | ||
| 2002 | unsigned int *val) | ||
| 2003 | { | ||
| 2004 | struct regmap *map = context; | ||
| 2005 | |||
| 2006 | return map->bus->reg_read(map->bus_context, reg, val); | ||
| 2007 | } | ||
| 2008 | |||
| 1983 | static int _regmap_bus_read(void *context, unsigned int reg, | 2009 | static int _regmap_bus_read(void *context, unsigned int reg, |
| 1984 | unsigned int *val) | 2010 | unsigned int *val) |
| 1985 | { | 2011 | { |
diff --git a/include/linux/regmap.h b/include/linux/regmap.h index 85691b9b4fa7..7b0e4b425cdf 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h | |||
| @@ -276,6 +276,10 @@ typedef int (*regmap_hw_async_write)(void *context, | |||
| 276 | typedef int (*regmap_hw_read)(void *context, | 276 | typedef int (*regmap_hw_read)(void *context, |
| 277 | const void *reg_buf, size_t reg_size, | 277 | const void *reg_buf, size_t reg_size, |
| 278 | void *val_buf, size_t val_size); | 278 | void *val_buf, size_t val_size); |
| 279 | typedef int (*regmap_hw_reg_read)(void *context, unsigned int reg, | ||
| 280 | unsigned int *val); | ||
| 281 | typedef int (*regmap_hw_reg_write)(void *context, unsigned int reg, | ||
| 282 | unsigned int val); | ||
| 279 | typedef struct regmap_async *(*regmap_hw_async_alloc)(void); | 283 | typedef struct regmap_async *(*regmap_hw_async_alloc)(void); |
| 280 | typedef void (*regmap_hw_free_context)(void *context); | 284 | typedef void (*regmap_hw_free_context)(void *context); |
| 281 | 285 | ||
| @@ -309,7 +313,9 @@ struct regmap_bus { | |||
| 309 | regmap_hw_write write; | 313 | regmap_hw_write write; |
| 310 | regmap_hw_gather_write gather_write; | 314 | regmap_hw_gather_write gather_write; |
| 311 | regmap_hw_async_write async_write; | 315 | regmap_hw_async_write async_write; |
| 316 | regmap_hw_reg_write reg_write; | ||
| 312 | regmap_hw_read read; | 317 | regmap_hw_read read; |
| 318 | regmap_hw_reg_read reg_read; | ||
| 313 | regmap_hw_free_context free_context; | 319 | regmap_hw_free_context free_context; |
| 314 | regmap_hw_async_alloc async_alloc; | 320 | regmap_hw_async_alloc async_alloc; |
| 315 | u8 read_flag_mask; | 321 | u8 read_flag_mask; |
