#include <linux/i2c.h>
 #include <linux/module.h>
 
+
+static int regmap_smbus_byte_reg_read(void *context, unsigned int reg,
+                                     unsigned int *val)
+{
+       struct device *dev = context;
+       struct i2c_client *i2c = to_i2c_client(dev);
+       int ret;
+
+       if (reg > 0xff)
+               return -EINVAL;
+
+       ret = i2c_smbus_read_byte_data(i2c, reg);
+       if (ret < 0)
+               return ret;
+
+       *val = ret;
+
+       return 0;
+}
+
+static int regmap_smbus_byte_reg_write(void *context, unsigned int reg,
+                                      unsigned int val)
+{
+       struct device *dev = context;
+       struct i2c_client *i2c = to_i2c_client(dev);
+
+       if (val > 0xff || reg > 0xff)
+               return -EINVAL;
+
+       return i2c_smbus_write_byte_data(i2c, reg, val);
+}
+
+static struct regmap_bus regmap_smbus_byte = {
+       .reg_write = regmap_smbus_byte_reg_write,
+       .reg_read = regmap_smbus_byte_reg_read,
+};
+
+static int regmap_smbus_word_reg_read(void *context, unsigned int reg,
+                                     unsigned int *val)
+{
+       struct device *dev = context;
+       struct i2c_client *i2c = to_i2c_client(dev);
+       int ret;
+
+       if (reg > 0xff)
+               return -EINVAL;
+
+       ret = i2c_smbus_read_word_data(i2c, reg);
+       if (ret < 0)
+               return ret;
+
+       *val = ret;
+
+       return 0;
+}
+
+static int regmap_smbus_word_reg_write(void *context, unsigned int reg,
+                                      unsigned int val)
+{
+       struct device *dev = context;
+       struct i2c_client *i2c = to_i2c_client(dev);
+
+       if (val > 0xffff || reg > 0xff)
+               return -EINVAL;
+
+       return i2c_smbus_write_word_data(i2c, reg, val);
+}
+
+static struct regmap_bus regmap_smbus_word = {
+       .reg_write = regmap_smbus_word_reg_write,
+       .reg_read = regmap_smbus_word_reg_read,
+};
+
 static int regmap_i2c_write(void *context, const void *data, size_t count)
 {
        struct device *dev = context;
        .read = regmap_i2c_read,
 };
 
+static const struct regmap_bus *regmap_get_i2c_bus(struct i2c_client *i2c,
+                                       const struct regmap_config *config)
+{
+       if (i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C))
+               return ®map_i2c;
+       else if (config->val_bits == 16 && config->reg_bits == 8 &&
+                i2c_check_functionality(i2c->adapter,
+                                        I2C_FUNC_SMBUS_WORD_DATA))
+               return ®map_smbus_word;
+       else if (config->val_bits == 8 && config->reg_bits == 8 &&
+                i2c_check_functionality(i2c->adapter,
+                                        I2C_FUNC_SMBUS_BYTE_DATA))
+               return ®map_smbus_byte;
+
+       return ERR_PTR(-ENOTSUPP);
+}
+
 /**
  * regmap_init_i2c(): Initialise register map
  *
 struct regmap *regmap_init_i2c(struct i2c_client *i2c,
                               const struct regmap_config *config)
 {
-       return regmap_init(&i2c->dev, ®map_i2c, &i2c->dev, config);
+       const struct regmap_bus *bus = regmap_get_i2c_bus(i2c, config);
+
+       if (IS_ERR(bus))
+               return ERR_CAST(bus);
+
+       return regmap_init(&i2c->dev, bus, &i2c->dev, config);
 }
 EXPORT_SYMBOL_GPL(regmap_init_i2c);
 
 struct regmap *devm_regmap_init_i2c(struct i2c_client *i2c,
                                    const struct regmap_config *config)
 {
-       return devm_regmap_init(&i2c->dev, ®map_i2c, &i2c->dev, config);
+       const struct regmap_bus *bus = regmap_get_i2c_bus(i2c, config);
+
+       if (IS_ERR(bus))
+               return ERR_CAST(bus);
+
+       return devm_regmap_init(&i2c->dev, bus, &i2c->dev, config);
 }
 EXPORT_SYMBOL_GPL(devm_regmap_init_i2c);