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) | (st->rx[2] << 8) | st->rx[3];
199out:
200	mutex_unlock(&st->buf_lock);
201	return ret;
202}
203
204static int ade7854_i2c_probe(struct i2c_client *client,
205		const struct i2c_device_id *id)
206{
207	int ret;
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 == NULL)
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	ret = ade7854_probe(indio_dev, &client->dev);
228
229	return ret;
230}
231
232static int ade7854_i2c_remove(struct i2c_client *client)
233{
234	return ade7854_remove(i2c_get_clientdata(client));
235}
236
237static const struct i2c_device_id ade7854_id[] = {
238	{ "ade7854", 0 },
239	{ "ade7858", 0 },
240	{ "ade7868", 0 },
241	{ "ade7878", 0 },
242	{ }
243};
244MODULE_DEVICE_TABLE(i2c, ade7854_id);
245
246static struct i2c_driver ade7854_i2c_driver = {
247	.driver = {
248		.name = "ade7854",
249	},
250	.probe    = ade7854_i2c_probe,
251	.remove   = ade7854_i2c_remove,
252	.id_table = ade7854_id,
253};
254module_i2c_driver(ade7854_i2c_driver);
255
256MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
257MODULE_DESCRIPTION("Analog Devices ADE7854/58/68/78 Polyphase Multifunction Energy Metering IC I2C Driver");
258MODULE_LICENSE("GPL v2");
259