1 /* 2 * Register map access API - I2C support 3 * 4 * Copyright 2011 Wolfson Microelectronics plc 5 * 6 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License version 2 as 10 * published by the Free Software Foundation. 11 */ 12 13 #include <linux/regmap.h> 14 #include <linux/i2c.h> 15 #include <linux/module.h> 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 90 static int regmap_i2c_write(void *context, const void *data, size_t count) 91 { 92 struct device *dev = context; 93 struct i2c_client *i2c = to_i2c_client(dev); 94 int ret; 95 96 ret = i2c_master_send(i2c, data, count); 97 if (ret == count) 98 return 0; 99 else if (ret < 0) 100 return ret; 101 else 102 return -EIO; 103 } 104 105 static int regmap_i2c_gather_write(void *context, 106 const void *reg, size_t reg_size, 107 const void *val, size_t val_size) 108 { 109 struct device *dev = context; 110 struct i2c_client *i2c = to_i2c_client(dev); 111 struct i2c_msg xfer[2]; 112 int ret; 113 114 /* If the I2C controller can't do a gather tell the core, it 115 * will substitute in a linear write for us. 116 */ 117 if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_NOSTART)) 118 return -ENOTSUPP; 119 120 xfer[0].addr = i2c->addr; 121 xfer[0].flags = 0; 122 xfer[0].len = reg_size; 123 xfer[0].buf = (void *)reg; 124 125 xfer[1].addr = i2c->addr; 126 xfer[1].flags = I2C_M_NOSTART; 127 xfer[1].len = val_size; 128 xfer[1].buf = (void *)val; 129 130 ret = i2c_transfer(i2c->adapter, xfer, 2); 131 if (ret == 2) 132 return 0; 133 if (ret < 0) 134 return ret; 135 else 136 return -EIO; 137 } 138 139 static int regmap_i2c_read(void *context, 140 const void *reg, size_t reg_size, 141 void *val, size_t val_size) 142 { 143 struct device *dev = context; 144 struct i2c_client *i2c = to_i2c_client(dev); 145 struct i2c_msg xfer[2]; 146 int ret; 147 148 xfer[0].addr = i2c->addr; 149 xfer[0].flags = 0; 150 xfer[0].len = reg_size; 151 xfer[0].buf = (void *)reg; 152 153 xfer[1].addr = i2c->addr; 154 xfer[1].flags = I2C_M_RD; 155 xfer[1].len = val_size; 156 xfer[1].buf = val; 157 158 ret = i2c_transfer(i2c->adapter, xfer, 2); 159 if (ret == 2) 160 return 0; 161 else if (ret < 0) 162 return ret; 163 else 164 return -EIO; 165 } 166 167 static struct regmap_bus regmap_i2c = { 168 .write = regmap_i2c_write, 169 .gather_write = regmap_i2c_gather_write, 170 .read = regmap_i2c_read, 171 }; 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 190 /** 191 * regmap_init_i2c(): Initialise register map 192 * 193 * @i2c: Device that will be interacted with 194 * @config: Configuration for register map 195 * 196 * The return value will be an ERR_PTR() on error or a valid pointer to 197 * a struct regmap. 198 */ 199 struct regmap *regmap_init_i2c(struct i2c_client *i2c, 200 const struct regmap_config *config) 201 { 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); 208 } 209 EXPORT_SYMBOL_GPL(regmap_init_i2c); 210 211 /** 212 * devm_regmap_init_i2c(): Initialise managed register map 213 * 214 * @i2c: Device that will be interacted with 215 * @config: Configuration for register map 216 * 217 * The return value will be an ERR_PTR() on error or a valid pointer 218 * to a struct regmap. The regmap will be automatically freed by the 219 * device management code. 220 */ 221 struct regmap *devm_regmap_init_i2c(struct i2c_client *i2c, 222 const struct regmap_config *config) 223 { 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); 230 } 231 EXPORT_SYMBOL_GPL(devm_regmap_init_i2c); 232 233 MODULE_LICENSE("GPL"); 234