Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.16-rc1 233 lines 5.5 kB view raw
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 18static 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 37static 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 49static struct regmap_bus regmap_smbus_byte = { 50 .reg_write = regmap_smbus_byte_reg_write, 51 .reg_read = regmap_smbus_byte_reg_read, 52}; 53 54static 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 73static 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 85static struct regmap_bus regmap_smbus_word = { 86 .reg_write = regmap_smbus_word_reg_write, 87 .reg_read = regmap_smbus_word_reg_read, 88}; 89 90static 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 105static 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 139static 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 167static struct regmap_bus regmap_i2c = { 168 .write = regmap_i2c_write, 169 .gather_write = regmap_i2c_gather_write, 170 .read = regmap_i2c_read, 171}; 172 173static 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 &regmap_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 &regmap_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 &regmap_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 */ 199struct 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} 209EXPORT_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 */ 221struct 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} 231EXPORT_SYMBOL_GPL(devm_regmap_init_i2c); 232 233MODULE_LICENSE("GPL");