xref: /openbmc/linux/drivers/mfd/88pm860x-i2c.c (revision 12eb4683)
1 /*
2  * I2C driver for Marvell 88PM860x
3  *
4  * Copyright (C) 2009 Marvell International Ltd.
5  * 	Haojian Zhuang <haojian.zhuang@marvell.com>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundation.
10  */
11 #include <linux/kernel.h>
12 #include <linux/module.h>
13 #include <linux/i2c.h>
14 #include <linux/regmap.h>
15 #include <linux/mfd/88pm860x.h>
16 
17 int pm860x_reg_read(struct i2c_client *i2c, int reg)
18 {
19 	struct pm860x_chip *chip = i2c_get_clientdata(i2c);
20 	struct regmap *map = (i2c == chip->client) ? chip->regmap
21 				: chip->regmap_companion;
22 	unsigned int data;
23 	int ret;
24 
25 	ret = regmap_read(map, reg, &data);
26 	if (ret < 0)
27 		return ret;
28 	else
29 		return (int)data;
30 }
31 EXPORT_SYMBOL(pm860x_reg_read);
32 
33 int pm860x_reg_write(struct i2c_client *i2c, int reg,
34 		     unsigned char data)
35 {
36 	struct pm860x_chip *chip = i2c_get_clientdata(i2c);
37 	struct regmap *map = (i2c == chip->client) ? chip->regmap
38 				: chip->regmap_companion;
39 	int ret;
40 
41 	ret = regmap_write(map, reg, data);
42 	return ret;
43 }
44 EXPORT_SYMBOL(pm860x_reg_write);
45 
46 int pm860x_bulk_read(struct i2c_client *i2c, int reg,
47 		     int count, unsigned char *buf)
48 {
49 	struct pm860x_chip *chip = i2c_get_clientdata(i2c);
50 	struct regmap *map = (i2c == chip->client) ? chip->regmap
51 				: chip->regmap_companion;
52 	int ret;
53 
54 	ret = regmap_raw_read(map, reg, buf, count);
55 	return ret;
56 }
57 EXPORT_SYMBOL(pm860x_bulk_read);
58 
59 int pm860x_bulk_write(struct i2c_client *i2c, int reg,
60 		      int count, unsigned char *buf)
61 {
62 	struct pm860x_chip *chip = i2c_get_clientdata(i2c);
63 	struct regmap *map = (i2c == chip->client) ? chip->regmap
64 				: chip->regmap_companion;
65 	int ret;
66 
67 	ret = regmap_raw_write(map, reg, buf, count);
68 	return ret;
69 }
70 EXPORT_SYMBOL(pm860x_bulk_write);
71 
72 int pm860x_set_bits(struct i2c_client *i2c, int reg,
73 		    unsigned char mask, unsigned char data)
74 {
75 	struct pm860x_chip *chip = i2c_get_clientdata(i2c);
76 	struct regmap *map = (i2c == chip->client) ? chip->regmap
77 				: chip->regmap_companion;
78 	int ret;
79 
80 	ret = regmap_update_bits(map, reg, mask, data);
81 	return ret;
82 }
83 EXPORT_SYMBOL(pm860x_set_bits);
84 
85 static int read_device(struct i2c_client *i2c, int reg,
86 		       int bytes, void *dest)
87 {
88 	unsigned char msgbuf0[I2C_SMBUS_BLOCK_MAX + 3];
89 	unsigned char msgbuf1[I2C_SMBUS_BLOCK_MAX + 2];
90 	struct i2c_adapter *adap = i2c->adapter;
91 	struct i2c_msg msg[2] = {
92 					{
93 						.addr = i2c->addr,
94 						.flags = 0,
95 						.len = 1,
96 						.buf = msgbuf0
97 					},
98 					{	.addr = i2c->addr,
99 						.flags = I2C_M_RD,
100 						.len = 0,
101 						.buf = msgbuf1
102 					},
103 				};
104 	int num = 1, ret = 0;
105 
106 	if (dest == NULL)
107 		return -EINVAL;
108 	msgbuf0[0] = (unsigned char)reg;	/* command */
109 	msg[1].len = bytes;
110 
111 	/* if data needs to read back, num should be 2 */
112 	if (bytes > 0)
113 		num = 2;
114 	ret = adap->algo->master_xfer(adap, msg, num);
115 	memcpy(dest, msgbuf1, bytes);
116 	if (ret < 0)
117 		return ret;
118 	return 0;
119 }
120 
121 static int write_device(struct i2c_client *i2c, int reg,
122 			int bytes, void *src)
123 {
124 	unsigned char buf[bytes + 1];
125 	struct i2c_adapter *adap = i2c->adapter;
126 	struct i2c_msg msg;
127 	int ret;
128 
129 	buf[0] = (unsigned char)reg;
130 	memcpy(&buf[1], src, bytes);
131 	msg.addr = i2c->addr;
132 	msg.flags = 0;
133 	msg.len = bytes + 1;
134 	msg.buf = buf;
135 
136 	ret = adap->algo->master_xfer(adap, &msg, 1);
137 	if (ret < 0)
138 		return ret;
139 	return 0;
140 }
141 
142 int pm860x_page_reg_read(struct i2c_client *i2c, int reg)
143 {
144 	unsigned char zero = 0;
145 	unsigned char data;
146 	int ret;
147 
148 	i2c_lock_adapter(i2c->adapter);
149 	read_device(i2c, 0xFA, 0, &zero);
150 	read_device(i2c, 0xFB, 0, &zero);
151 	read_device(i2c, 0xFF, 0, &zero);
152 	ret = read_device(i2c, reg, 1, &data);
153 	if (ret >= 0)
154 		ret = (int)data;
155 	read_device(i2c, 0xFE, 0, &zero);
156 	read_device(i2c, 0xFC, 0, &zero);
157 	i2c_unlock_adapter(i2c->adapter);
158 	return ret;
159 }
160 EXPORT_SYMBOL(pm860x_page_reg_read);
161 
162 int pm860x_page_reg_write(struct i2c_client *i2c, int reg,
163 			  unsigned char data)
164 {
165 	unsigned char zero;
166 	int ret;
167 
168 	i2c_lock_adapter(i2c->adapter);
169 	read_device(i2c, 0xFA, 0, &zero);
170 	read_device(i2c, 0xFB, 0, &zero);
171 	read_device(i2c, 0xFF, 0, &zero);
172 	ret = write_device(i2c, reg, 1, &data);
173 	read_device(i2c, 0xFE, 0, &zero);
174 	read_device(i2c, 0xFC, 0, &zero);
175 	i2c_unlock_adapter(i2c->adapter);
176 	return ret;
177 }
178 EXPORT_SYMBOL(pm860x_page_reg_write);
179 
180 int pm860x_page_bulk_read(struct i2c_client *i2c, int reg,
181 			  int count, unsigned char *buf)
182 {
183 	unsigned char zero = 0;
184 	int ret;
185 
186 	i2c_lock_adapter(i2c->adapter);
187 	read_device(i2c, 0xfa, 0, &zero);
188 	read_device(i2c, 0xfb, 0, &zero);
189 	read_device(i2c, 0xff, 0, &zero);
190 	ret = read_device(i2c, reg, count, buf);
191 	read_device(i2c, 0xFE, 0, &zero);
192 	read_device(i2c, 0xFC, 0, &zero);
193 	i2c_unlock_adapter(i2c->adapter);
194 	return ret;
195 }
196 EXPORT_SYMBOL(pm860x_page_bulk_read);
197 
198 int pm860x_page_bulk_write(struct i2c_client *i2c, int reg,
199 			   int count, unsigned char *buf)
200 {
201 	unsigned char zero = 0;
202 	int ret;
203 
204 	i2c_lock_adapter(i2c->adapter);
205 	read_device(i2c, 0xFA, 0, &zero);
206 	read_device(i2c, 0xFB, 0, &zero);
207 	read_device(i2c, 0xFF, 0, &zero);
208 	ret = write_device(i2c, reg, count, buf);
209 	read_device(i2c, 0xFE, 0, &zero);
210 	read_device(i2c, 0xFC, 0, &zero);
211 	i2c_unlock_adapter(i2c->adapter);
212 	i2c_unlock_adapter(i2c->adapter);
213 	return ret;
214 }
215 EXPORT_SYMBOL(pm860x_page_bulk_write);
216 
217 int pm860x_page_set_bits(struct i2c_client *i2c, int reg,
218 			 unsigned char mask, unsigned char data)
219 {
220 	unsigned char zero;
221 	unsigned char value;
222 	int ret;
223 
224 	i2c_lock_adapter(i2c->adapter);
225 	read_device(i2c, 0xFA, 0, &zero);
226 	read_device(i2c, 0xFB, 0, &zero);
227 	read_device(i2c, 0xFF, 0, &zero);
228 	ret = read_device(i2c, reg, 1, &value);
229 	if (ret < 0)
230 		goto out;
231 	value &= ~mask;
232 	value |= data;
233 	ret = write_device(i2c, reg, 1, &value);
234 out:
235 	read_device(i2c, 0xFE, 0, &zero);
236 	read_device(i2c, 0xFC, 0, &zero);
237 	i2c_unlock_adapter(i2c->adapter);
238 	return ret;
239 }
240 EXPORT_SYMBOL(pm860x_page_set_bits);
241