Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/base/regmap/regmap-i2c.c
26427 views
1
// SPDX-License-Identifier: GPL-2.0
2
//
3
// Register map access API - I2C support
4
//
5
// Copyright 2011 Wolfson Microelectronics plc
6
//
7
// Author: Mark Brown <[email protected]>
8
9
#include <linux/regmap.h>
10
#include <linux/i2c.h>
11
#include <linux/module.h>
12
13
#include "internal.h"
14
15
static int regmap_smbus_byte_reg_read(void *context, unsigned int reg,
16
unsigned int *val)
17
{
18
struct device *dev = context;
19
struct i2c_client *i2c = to_i2c_client(dev);
20
int ret;
21
22
if (reg > 0xff)
23
return -EINVAL;
24
25
ret = i2c_smbus_read_byte_data(i2c, reg);
26
if (ret < 0)
27
return ret;
28
29
*val = ret;
30
31
return 0;
32
}
33
34
static int regmap_smbus_byte_reg_write(void *context, unsigned int reg,
35
unsigned int val)
36
{
37
struct device *dev = context;
38
struct i2c_client *i2c = to_i2c_client(dev);
39
40
if (val > 0xff || reg > 0xff)
41
return -EINVAL;
42
43
return i2c_smbus_write_byte_data(i2c, reg, val);
44
}
45
46
static const struct regmap_bus regmap_smbus_byte = {
47
.reg_write = regmap_smbus_byte_reg_write,
48
.reg_read = regmap_smbus_byte_reg_read,
49
};
50
51
static int regmap_smbus_word_reg_read(void *context, unsigned int reg,
52
unsigned int *val)
53
{
54
struct device *dev = context;
55
struct i2c_client *i2c = to_i2c_client(dev);
56
int ret;
57
58
if (reg > 0xff)
59
return -EINVAL;
60
61
ret = i2c_smbus_read_word_data(i2c, reg);
62
if (ret < 0)
63
return ret;
64
65
*val = ret;
66
67
return 0;
68
}
69
70
static int regmap_smbus_word_reg_write(void *context, unsigned int reg,
71
unsigned int val)
72
{
73
struct device *dev = context;
74
struct i2c_client *i2c = to_i2c_client(dev);
75
76
if (val > 0xffff || reg > 0xff)
77
return -EINVAL;
78
79
return i2c_smbus_write_word_data(i2c, reg, val);
80
}
81
82
static const struct regmap_bus regmap_smbus_word = {
83
.reg_write = regmap_smbus_word_reg_write,
84
.reg_read = regmap_smbus_word_reg_read,
85
};
86
87
static int regmap_smbus_word_read_swapped(void *context, unsigned int reg,
88
unsigned int *val)
89
{
90
struct device *dev = context;
91
struct i2c_client *i2c = to_i2c_client(dev);
92
int ret;
93
94
if (reg > 0xff)
95
return -EINVAL;
96
97
ret = i2c_smbus_read_word_swapped(i2c, reg);
98
if (ret < 0)
99
return ret;
100
101
*val = ret;
102
103
return 0;
104
}
105
106
static int regmap_smbus_word_write_swapped(void *context, unsigned int reg,
107
unsigned int val)
108
{
109
struct device *dev = context;
110
struct i2c_client *i2c = to_i2c_client(dev);
111
112
if (val > 0xffff || reg > 0xff)
113
return -EINVAL;
114
115
return i2c_smbus_write_word_swapped(i2c, reg, val);
116
}
117
118
static const struct regmap_bus regmap_smbus_word_swapped = {
119
.reg_write = regmap_smbus_word_write_swapped,
120
.reg_read = regmap_smbus_word_read_swapped,
121
};
122
123
static int regmap_i2c_write(void *context, const void *data, size_t count)
124
{
125
struct device *dev = context;
126
struct i2c_client *i2c = to_i2c_client(dev);
127
int ret;
128
129
ret = i2c_master_send(i2c, data, count);
130
if (ret == count)
131
return 0;
132
else if (ret < 0)
133
return ret;
134
else
135
return -EIO;
136
}
137
138
static int regmap_i2c_gather_write(void *context,
139
const void *reg, size_t reg_size,
140
const void *val, size_t val_size)
141
{
142
struct device *dev = context;
143
struct i2c_client *i2c = to_i2c_client(dev);
144
struct i2c_msg xfer[2];
145
int ret;
146
147
/* If the I2C controller can't do a gather tell the core, it
148
* will substitute in a linear write for us.
149
*/
150
if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_NOSTART))
151
return -ENOTSUPP;
152
153
xfer[0].addr = i2c->addr;
154
xfer[0].flags = 0;
155
xfer[0].len = reg_size;
156
xfer[0].buf = (void *)reg;
157
158
xfer[1].addr = i2c->addr;
159
xfer[1].flags = I2C_M_NOSTART;
160
xfer[1].len = val_size;
161
xfer[1].buf = (void *)val;
162
163
ret = i2c_transfer(i2c->adapter, xfer, 2);
164
if (ret == 2)
165
return 0;
166
if (ret < 0)
167
return ret;
168
else
169
return -EIO;
170
}
171
172
static int regmap_i2c_read(void *context,
173
const void *reg, size_t reg_size,
174
void *val, size_t val_size)
175
{
176
struct device *dev = context;
177
struct i2c_client *i2c = to_i2c_client(dev);
178
struct i2c_msg xfer[2];
179
int ret;
180
181
xfer[0].addr = i2c->addr;
182
xfer[0].flags = 0;
183
xfer[0].len = reg_size;
184
xfer[0].buf = (void *)reg;
185
186
xfer[1].addr = i2c->addr;
187
xfer[1].flags = I2C_M_RD;
188
xfer[1].len = val_size;
189
xfer[1].buf = val;
190
191
ret = i2c_transfer(i2c->adapter, xfer, 2);
192
if (ret == 2)
193
return 0;
194
else if (ret < 0)
195
return ret;
196
else
197
return -EIO;
198
}
199
200
static const struct regmap_bus regmap_i2c = {
201
.write = regmap_i2c_write,
202
.gather_write = regmap_i2c_gather_write,
203
.read = regmap_i2c_read,
204
.reg_format_endian_default = REGMAP_ENDIAN_BIG,
205
.val_format_endian_default = REGMAP_ENDIAN_BIG,
206
};
207
208
static int regmap_i2c_smbus_i2c_write(void *context, const void *data,
209
size_t count)
210
{
211
struct device *dev = context;
212
struct i2c_client *i2c = to_i2c_client(dev);
213
214
if (count < 1)
215
return -EINVAL;
216
217
--count;
218
return i2c_smbus_write_i2c_block_data(i2c, ((u8 *)data)[0], count,
219
((u8 *)data + 1));
220
}
221
222
static int regmap_i2c_smbus_i2c_read(void *context, const void *reg,
223
size_t reg_size, void *val,
224
size_t val_size)
225
{
226
struct device *dev = context;
227
struct i2c_client *i2c = to_i2c_client(dev);
228
int ret;
229
230
if (reg_size != 1 || val_size < 1)
231
return -EINVAL;
232
233
ret = i2c_smbus_read_i2c_block_data(i2c, ((u8 *)reg)[0], val_size, val);
234
if (ret == val_size)
235
return 0;
236
else if (ret < 0)
237
return ret;
238
else
239
return -EIO;
240
}
241
242
static const struct regmap_bus regmap_i2c_smbus_i2c_block = {
243
.write = regmap_i2c_smbus_i2c_write,
244
.read = regmap_i2c_smbus_i2c_read,
245
.max_raw_read = I2C_SMBUS_BLOCK_MAX - 1,
246
.max_raw_write = I2C_SMBUS_BLOCK_MAX - 1,
247
};
248
249
static int regmap_i2c_smbus_i2c_write_reg16(void *context, const void *data,
250
size_t count)
251
{
252
struct device *dev = context;
253
struct i2c_client *i2c = to_i2c_client(dev);
254
255
if (count < 2)
256
return -EINVAL;
257
258
count--;
259
return i2c_smbus_write_i2c_block_data(i2c, ((u8 *)data)[0], count,
260
(u8 *)data + 1);
261
}
262
263
static int regmap_i2c_smbus_i2c_read_reg16(void *context, const void *reg,
264
size_t reg_size, void *val,
265
size_t val_size)
266
{
267
struct device *dev = context;
268
struct i2c_client *i2c = to_i2c_client(dev);
269
int ret, count, len = val_size;
270
271
if (reg_size != 2)
272
return -EINVAL;
273
274
ret = i2c_smbus_write_byte_data(i2c, ((u16 *)reg)[0] & 0xff,
275
((u16 *)reg)[0] >> 8);
276
if (ret < 0)
277
return ret;
278
279
count = 0;
280
do {
281
/* Current Address Read */
282
ret = i2c_smbus_read_byte(i2c);
283
if (ret < 0)
284
break;
285
286
*((u8 *)val++) = ret;
287
count++;
288
len--;
289
} while (len > 0);
290
291
if (count == val_size)
292
return 0;
293
else if (ret < 0)
294
return ret;
295
else
296
return -EIO;
297
}
298
299
static const struct regmap_bus regmap_i2c_smbus_i2c_block_reg16 = {
300
.write = regmap_i2c_smbus_i2c_write_reg16,
301
.read = regmap_i2c_smbus_i2c_read_reg16,
302
.max_raw_read = I2C_SMBUS_BLOCK_MAX - 2,
303
.max_raw_write = I2C_SMBUS_BLOCK_MAX - 2,
304
};
305
306
static const struct regmap_bus *regmap_get_i2c_bus(struct i2c_client *i2c,
307
const struct regmap_config *config)
308
{
309
const struct i2c_adapter_quirks *quirks;
310
const struct regmap_bus *bus = NULL;
311
struct regmap_bus *ret_bus;
312
u16 max_read = 0, max_write = 0;
313
314
if (i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C))
315
bus = &regmap_i2c;
316
else if (config->val_bits == 8 && config->reg_bits == 8 &&
317
i2c_check_functionality(i2c->adapter,
318
I2C_FUNC_SMBUS_I2C_BLOCK))
319
bus = &regmap_i2c_smbus_i2c_block;
320
else if (config->val_bits == 8 && config->reg_bits == 16 &&
321
i2c_check_functionality(i2c->adapter,
322
I2C_FUNC_SMBUS_I2C_BLOCK))
323
bus = &regmap_i2c_smbus_i2c_block_reg16;
324
else if (config->val_bits == 16 && config->reg_bits == 8 &&
325
i2c_check_functionality(i2c->adapter,
326
I2C_FUNC_SMBUS_WORD_DATA))
327
switch (regmap_get_val_endian(&i2c->dev, NULL, config)) {
328
case REGMAP_ENDIAN_LITTLE:
329
bus = &regmap_smbus_word;
330
break;
331
case REGMAP_ENDIAN_BIG:
332
bus = &regmap_smbus_word_swapped;
333
break;
334
default: /* everything else is not supported */
335
break;
336
}
337
else if (config->val_bits == 8 && config->reg_bits == 8 &&
338
i2c_check_functionality(i2c->adapter,
339
I2C_FUNC_SMBUS_BYTE_DATA))
340
bus = &regmap_smbus_byte;
341
342
if (!bus)
343
return ERR_PTR(-ENOTSUPP);
344
345
quirks = i2c->adapter->quirks;
346
if (quirks) {
347
if (quirks->max_read_len &&
348
(bus->max_raw_read == 0 || bus->max_raw_read > quirks->max_read_len))
349
max_read = quirks->max_read_len;
350
351
if (quirks->max_write_len &&
352
(bus->max_raw_write == 0 || bus->max_raw_write > quirks->max_write_len))
353
max_write = quirks->max_write_len -
354
(config->reg_bits + config->pad_bits) / BITS_PER_BYTE;
355
356
if (max_read || max_write) {
357
ret_bus = kmemdup(bus, sizeof(*bus), GFP_KERNEL);
358
if (!ret_bus)
359
return ERR_PTR(-ENOMEM);
360
ret_bus->free_on_exit = true;
361
ret_bus->max_raw_read = max_read;
362
ret_bus->max_raw_write = max_write;
363
bus = ret_bus;
364
}
365
}
366
367
return bus;
368
}
369
370
struct regmap *__regmap_init_i2c(struct i2c_client *i2c,
371
const struct regmap_config *config,
372
struct lock_class_key *lock_key,
373
const char *lock_name)
374
{
375
const struct regmap_bus *bus = regmap_get_i2c_bus(i2c, config);
376
377
if (IS_ERR(bus))
378
return ERR_CAST(bus);
379
380
return __regmap_init(&i2c->dev, bus, &i2c->dev, config,
381
lock_key, lock_name);
382
}
383
EXPORT_SYMBOL_GPL(__regmap_init_i2c);
384
385
struct regmap *__devm_regmap_init_i2c(struct i2c_client *i2c,
386
const struct regmap_config *config,
387
struct lock_class_key *lock_key,
388
const char *lock_name)
389
{
390
const struct regmap_bus *bus = regmap_get_i2c_bus(i2c, config);
391
392
if (IS_ERR(bus))
393
return ERR_CAST(bus);
394
395
return __devm_regmap_init(&i2c->dev, bus, &i2c->dev, config,
396
lock_key, lock_name);
397
}
398
EXPORT_SYMBOL_GPL(__devm_regmap_init_i2c);
399
400
MODULE_DESCRIPTION("Register map access API - I2C support");
401
MODULE_LICENSE("GPL");
402
403