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