1/*
2 * ADE7854/58/68/78 Polyphase Multifunction Energy Metering IC Driver (I2C Bus)
3 *
4 * Copyright 2010 Analog Devices Inc.
5 *
6 * Licensed under the GPL-2 or later.
7 */
8
9#include <linux/device.h>
10#include <linux/kernel.h>
11#include <linux/i2c.h>
12#include <linux/slab.h>
13#include <linux/module.h>
14
15#include <linux/iio/iio.h>
16#include "ade7854.h"
17
18static int ade7854_i2c_write_reg_8(struct device *dev,
19				   u16 reg_address,
20				   u8 value)
21{
22	int ret;
23	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
24	struct ade7854_state *st = iio_priv(indio_dev);
25
26	mutex_lock(&st->buf_lock);
27	st->tx[0] = (reg_address >> 8) & 0xFF;
28	st->tx[1] = reg_address & 0xFF;
29	st->tx[2] = value;
30
31	ret = i2c_master_send(st->i2c, st->tx, 3);
32	mutex_unlock(&st->buf_lock);
33
34	return ret;
35}
36
37static int ade7854_i2c_write_reg_16(struct device *dev,
38				    u16 reg_address,
39				    u16 value)
40{
41	int ret;
42	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
43	struct ade7854_state *st = iio_priv(indio_dev);
44
45	mutex_lock(&st->buf_lock);
46	st->tx[0] = (reg_address >> 8) & 0xFF;
47	st->tx[1] = reg_address & 0xFF;
48	st->tx[2] = (value >> 8) & 0xFF;
49	st->tx[3] = value & 0xFF;
50
51	ret = i2c_master_send(st->i2c, st->tx, 4);
52	mutex_unlock(&st->buf_lock);
53
54	return ret;
55}
56
57static int ade7854_i2c_write_reg_24(struct device *dev,
58				    u16 reg_address,
59				    u32 value)
60{
61	int ret;
62	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
63	struct ade7854_state *st = iio_priv(indio_dev);
64
65	mutex_lock(&st->buf_lock);
66	st->tx[0] = (reg_address >> 8) & 0xFF;
67	st->tx[1] = reg_address & 0xFF;
68	st->tx[2] = (value >> 16) & 0xFF;
69	st->tx[3] = (value >> 8) & 0xFF;
70	st->tx[4] = value & 0xFF;
71
72	ret = i2c_master_send(st->i2c, st->tx, 5);
73	mutex_unlock(&st->buf_lock);
74
75	return ret;
76}
77
78static int ade7854_i2c_write_reg_32(struct device *dev,
79				    u16 reg_address,
80				    u32 value)
81{
82	int ret;
83	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
84	struct ade7854_state *st = iio_priv(indio_dev);
85
86	mutex_lock(&st->buf_lock);
87	st->tx[0] = (reg_address >> 8) & 0xFF;
88	st->tx[1] = reg_address & 0xFF;
89	st->tx[2] = (value >> 24) & 0xFF;
90	st->tx[3] = (value >> 16) & 0xFF;
91	st->tx[4] = (value >> 8) & 0xFF;
92	st->tx[5] = value & 0xFF;
93
94	ret = i2c_master_send(st->i2c, st->tx, 6);
95	mutex_unlock(&st->buf_lock);
96
97	return ret;
98}
99
100static int ade7854_i2c_read_reg_8(struct device *dev,
101				  u16 reg_address,
102				  u8 *val)
103{
104	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
105	struct ade7854_state *st = iio_priv(indio_dev);
106	int ret;
107
108	mutex_lock(&st->buf_lock);
109	st->tx[0] = (reg_address >> 8) & 0xFF;
110	st->tx[1] = reg_address & 0xFF;
111
112	ret = i2c_master_send(st->i2c, st->tx, 2);
113	if (ret)
114		goto out;
115
116	ret = i2c_master_recv(st->i2c, st->rx, 1);
117	if (ret)
118		goto out;
119
120	*val = st->rx[0];
121out:
122	mutex_unlock(&st->buf_lock);
123	return ret;
124}
125
126static int ade7854_i2c_read_reg_16(struct device *dev,
127				   u16 reg_address,
128				   u16 *val)
129{
130	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
131	struct ade7854_state *st = iio_priv(indio_dev);
132	int ret;
133
134	mutex_lock(&st->buf_lock);
135	st->tx[0] = (reg_address >> 8) & 0xFF;
136	st->tx[1] = reg_address & 0xFF;
137
138	ret = i2c_master_send(st->i2c, st->tx, 2);
139	if (ret)
140		goto out;
141
142	ret = i2c_master_recv(st->i2c, st->rx, 2);
143	if (ret)
144		goto out;
145
146	*val = (st->rx[0] << 8) | st->rx[1];
147out:
148	mutex_unlock(&st->buf_lock);
149	return ret;
150}
151
152static int ade7854_i2c_read_reg_24(struct device *dev,
153				   u16 reg_address,
154				   u32 *val)
155{
156	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
157	struct ade7854_state *st = iio_priv(indio_dev);
158	int ret;
159
160	mutex_lock(&st->buf_lock);
161	st->tx[0] = (reg_address >> 8) & 0xFF;
162	st->tx[1] = reg_address & 0xFF;
163
164	ret = i2c_master_send(st->i2c, st->tx, 2);
165	if (ret)
166		goto out;
167
168	ret = i2c_master_recv(st->i2c, st->rx, 3);
169	if (ret)
170		goto out;
171
172	*val = (st->rx[0] << 16) | (st->rx[1] << 8) | st->rx[2];
173out:
174	mutex_unlock(&st->buf_lock);
175	return ret;
176}
177
178static int ade7854_i2c_read_reg_32(struct device *dev,
179				   u16 reg_address,
180				   u32 *val)
181{
182	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
183	struct ade7854_state *st = iio_priv(indio_dev);
184	int ret;
185
186	mutex_lock(&st->buf_lock);
187	st->tx[0] = (reg_address >> 8) & 0xFF;
188	st->tx[1] = reg_address & 0xFF;
189
190	ret = i2c_master_send(st->i2c, st->tx, 2);
191	if (ret)
192		goto out;
193
194	ret = i2c_master_recv(st->i2c, st->rx, 3);
195	if (ret)
196		goto out;
197
198	*val = (st->rx[0] << 24) | (st->rx[1] << 16) |
199		(st->rx[2] << 8) | st->rx[3];
200out:
201	mutex_unlock(&st->buf_lock);
202	return ret;
203}
204
205static int ade7854_i2c_probe(struct i2c_client *client,
206			     const struct i2c_device_id *id)
207{
208	struct ade7854_state *st;
209	struct iio_dev *indio_dev;
210
211	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*st));
212	if (!indio_dev)
213		return -ENOMEM;
214	st = iio_priv(indio_dev);
215	i2c_set_clientdata(client, indio_dev);
216	st->read_reg_8 = ade7854_i2c_read_reg_8;
217	st->read_reg_16 = ade7854_i2c_read_reg_16;
218	st->read_reg_24 = ade7854_i2c_read_reg_24;
219	st->read_reg_32 = ade7854_i2c_read_reg_32;
220	st->write_reg_8 = ade7854_i2c_write_reg_8;
221	st->write_reg_16 = ade7854_i2c_write_reg_16;
222	st->write_reg_24 = ade7854_i2c_write_reg_24;
223	st->write_reg_32 = ade7854_i2c_write_reg_32;
224	st->i2c = client;
225	st->irq = client->irq;
226
227	return ade7854_probe(indio_dev, &client->dev);
228}
229
230static int ade7854_i2c_remove(struct i2c_client *client)
231{
232	return ade7854_remove(i2c_get_clientdata(client));
233}
234
235static const struct i2c_device_id ade7854_id[] = {
236	{ "ade7854", 0 },
237	{ "ade7858", 0 },
238	{ "ade7868", 0 },
239	{ "ade7878", 0 },
240	{ }
241};
242MODULE_DEVICE_TABLE(i2c, ade7854_id);
243
244static struct i2c_driver ade7854_i2c_driver = {
245	.driver = {
246		.name = "ade7854",
247	},
248	.probe    = ade7854_i2c_probe,
249	.remove   = ade7854_i2c_remove,
250	.id_table = ade7854_id,
251};
252module_i2c_driver(ade7854_i2c_driver);
253
254MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
255MODULE_DESCRIPTION("Analog Devices ADE7854/58/68/78 Polyphase Multifunction Energy Metering IC I2C Driver");
256MODULE_LICENSE("GPL v2");
257