1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * ADE7854/58/68/78 Polyphase Multifunction Energy Metering IC Driver (I2C Bus)
4 *
5 * Copyright 2010 Analog Devices Inc.
6 */
7
8 #include <linux/device.h>
9 #include <linux/kernel.h>
10 #include <linux/i2c.h>
11 #include <linux/slab.h>
12 #include <linux/module.h>
13
14 #include <linux/iio/iio.h>
15 #include "ade7854.h"
16
ade7854_i2c_write_reg(struct device * dev,u16 reg_address,u32 val,int bits)17 static int ade7854_i2c_write_reg(struct device *dev,
18 u16 reg_address,
19 u32 val,
20 int bits)
21 {
22 int ret;
23 int count;
24 struct iio_dev *indio_dev = dev_to_iio_dev(dev);
25 struct ade7854_state *st = iio_priv(indio_dev);
26
27 mutex_lock(&st->buf_lock);
28 st->tx[0] = (reg_address >> 8) & 0xFF;
29 st->tx[1] = reg_address & 0xFF;
30
31 switch (bits) {
32 case 8:
33 st->tx[2] = val & 0xFF;
34 count = 3;
35 break;
36 case 16:
37 st->tx[2] = (val >> 8) & 0xFF;
38 st->tx[3] = val & 0xFF;
39 count = 4;
40 break;
41 case 24:
42 st->tx[2] = (val >> 16) & 0xFF;
43 st->tx[3] = (val >> 8) & 0xFF;
44 st->tx[4] = val & 0xFF;
45 count = 5;
46 break;
47 case 32:
48 st->tx[2] = (val >> 24) & 0xFF;
49 st->tx[3] = (val >> 16) & 0xFF;
50 st->tx[4] = (val >> 8) & 0xFF;
51 st->tx[5] = val & 0xFF;
52 count = 6;
53 break;
54 default:
55 ret = -EINVAL;
56 goto unlock;
57 }
58
59 ret = i2c_master_send(st->i2c, st->tx, count);
60
61 unlock:
62 mutex_unlock(&st->buf_lock);
63
64 if (ret < 0)
65 return ret;
66
67 return 0;
68 }
69
ade7854_i2c_read_reg(struct device * dev,u16 reg_address,u32 * val,int bits)70 static int ade7854_i2c_read_reg(struct device *dev,
71 u16 reg_address,
72 u32 *val,
73 int bits)
74 {
75 struct iio_dev *indio_dev = dev_to_iio_dev(dev);
76 struct ade7854_state *st = iio_priv(indio_dev);
77 int ret;
78
79 mutex_lock(&st->buf_lock);
80 st->tx[0] = (reg_address >> 8) & 0xFF;
81 st->tx[1] = reg_address & 0xFF;
82
83 ret = i2c_master_send(st->i2c, st->tx, 2);
84 if (ret < 0)
85 goto unlock;
86
87 ret = i2c_master_recv(st->i2c, st->rx, bits);
88 if (ret < 0)
89 goto unlock;
90
91 switch (bits) {
92 case 8:
93 *val = st->rx[0];
94 break;
95 case 16:
96 *val = (st->rx[0] << 8) | st->rx[1];
97 break;
98 case 24:
99 *val = (st->rx[0] << 16) | (st->rx[1] << 8) | st->rx[2];
100 break;
101 case 32:
102 *val = (st->rx[0] << 24) | (st->rx[1] << 16) |
103 (st->rx[2] << 8) | st->rx[3];
104 break;
105 default:
106 ret = -EINVAL;
107 goto unlock;
108 }
109
110 unlock:
111 mutex_unlock(&st->buf_lock);
112 return ret;
113 }
114
ade7854_i2c_probe(struct i2c_client * client)115 static int ade7854_i2c_probe(struct i2c_client *client)
116 {
117 struct ade7854_state *st;
118 struct iio_dev *indio_dev;
119
120 indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*st));
121 if (!indio_dev)
122 return -ENOMEM;
123 st = iio_priv(indio_dev);
124 i2c_set_clientdata(client, indio_dev);
125 st->read_reg = ade7854_i2c_read_reg;
126 st->write_reg = ade7854_i2c_write_reg;
127 st->i2c = client;
128 st->irq = client->irq;
129
130 return ade7854_probe(indio_dev, &client->dev);
131 }
132
133 static const struct i2c_device_id ade7854_id[] = {
134 { "ade7854", 0 },
135 { "ade7858", 0 },
136 { "ade7868", 0 },
137 { "ade7878", 0 },
138 { }
139 };
140 MODULE_DEVICE_TABLE(i2c, ade7854_id);
141
142 static struct i2c_driver ade7854_i2c_driver = {
143 .driver = {
144 .name = "ade7854",
145 },
146 .probe_new = ade7854_i2c_probe,
147 .id_table = ade7854_id,
148 };
149 module_i2c_driver(ade7854_i2c_driver);
150
151 MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
152 MODULE_DESCRIPTION("Analog Devices ADE7854/58/68/78 Polyphase Multifunction Energy Metering IC I2C Driver");
153 MODULE_LICENSE("GPL v2");
154