xref: /openbmc/linux/drivers/base/regmap/regmap-i2c.c (revision b34e08d5)
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 static int regmap_i2c_write(void *context, const void *data, size_t count)
18 {
19 	struct device *dev = context;
20 	struct i2c_client *i2c = to_i2c_client(dev);
21 	int ret;
22 
23 	ret = i2c_master_send(i2c, data, count);
24 	if (ret == count)
25 		return 0;
26 	else if (ret < 0)
27 		return ret;
28 	else
29 		return -EIO;
30 }
31 
32 static int regmap_i2c_gather_write(void *context,
33 				   const void *reg, size_t reg_size,
34 				   const void *val, size_t val_size)
35 {
36 	struct device *dev = context;
37 	struct i2c_client *i2c = to_i2c_client(dev);
38 	struct i2c_msg xfer[2];
39 	int ret;
40 
41 	/* If the I2C controller can't do a gather tell the core, it
42 	 * will substitute in a linear write for us.
43 	 */
44 	if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_NOSTART))
45 		return -ENOTSUPP;
46 
47 	xfer[0].addr = i2c->addr;
48 	xfer[0].flags = 0;
49 	xfer[0].len = reg_size;
50 	xfer[0].buf = (void *)reg;
51 
52 	xfer[1].addr = i2c->addr;
53 	xfer[1].flags = I2C_M_NOSTART;
54 	xfer[1].len = val_size;
55 	xfer[1].buf = (void *)val;
56 
57 	ret = i2c_transfer(i2c->adapter, xfer, 2);
58 	if (ret == 2)
59 		return 0;
60 	if (ret < 0)
61 		return ret;
62 	else
63 		return -EIO;
64 }
65 
66 static int regmap_i2c_read(void *context,
67 			   const void *reg, size_t reg_size,
68 			   void *val, size_t val_size)
69 {
70 	struct device *dev = context;
71 	struct i2c_client *i2c = to_i2c_client(dev);
72 	struct i2c_msg xfer[2];
73 	int ret;
74 
75 	xfer[0].addr = i2c->addr;
76 	xfer[0].flags = 0;
77 	xfer[0].len = reg_size;
78 	xfer[0].buf = (void *)reg;
79 
80 	xfer[1].addr = i2c->addr;
81 	xfer[1].flags = I2C_M_RD;
82 	xfer[1].len = val_size;
83 	xfer[1].buf = val;
84 
85 	ret = i2c_transfer(i2c->adapter, xfer, 2);
86 	if (ret == 2)
87 		return 0;
88 	else if (ret < 0)
89 		return ret;
90 	else
91 		return -EIO;
92 }
93 
94 static struct regmap_bus regmap_i2c = {
95 	.write = regmap_i2c_write,
96 	.gather_write = regmap_i2c_gather_write,
97 	.read = regmap_i2c_read,
98 };
99 
100 /**
101  * regmap_init_i2c(): Initialise register map
102  *
103  * @i2c: Device that will be interacted with
104  * @config: Configuration for register map
105  *
106  * The return value will be an ERR_PTR() on error or a valid pointer to
107  * a struct regmap.
108  */
109 struct regmap *regmap_init_i2c(struct i2c_client *i2c,
110 			       const struct regmap_config *config)
111 {
112 	return regmap_init(&i2c->dev, &regmap_i2c, &i2c->dev, config);
113 }
114 EXPORT_SYMBOL_GPL(regmap_init_i2c);
115 
116 /**
117  * devm_regmap_init_i2c(): Initialise managed register map
118  *
119  * @i2c: Device that will be interacted with
120  * @config: Configuration for register map
121  *
122  * The return value will be an ERR_PTR() on error or a valid pointer
123  * to a struct regmap.  The regmap will be automatically freed by the
124  * device management code.
125  */
126 struct regmap *devm_regmap_init_i2c(struct i2c_client *i2c,
127 				    const struct regmap_config *config)
128 {
129 	return devm_regmap_init(&i2c->dev, &regmap_i2c, &i2c->dev, config);
130 }
131 EXPORT_SYMBOL_GPL(devm_regmap_init_i2c);
132 
133 MODULE_LICENSE("GPL");
134