|
@@ -14,6 +14,79 @@
|
|
|
#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;
|
|
@@ -97,6 +170,23 @@ static struct regmap_bus regmap_i2c = {
|
|
|
.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
|
|
|
*
|
|
@@ -109,7 +199,12 @@ static struct regmap_bus regmap_i2c = {
|
|
|
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);
|
|
|
|
|
@@ -126,7 +221,12 @@ 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);
|
|
|
|