Merge branch 'core-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-2.6-block.git] / drivers / staging / iio / meter / ade7854-i2c.c
CommitLineData
2506abea 1// SPDX-License-Identifier: GPL-2.0+
5b264a62
BS
2/*
3 * ADE7854/58/68/78 Polyphase Multifunction Energy Metering IC Driver (I2C Bus)
4 *
5 * Copyright 2010 Analog Devices Inc.
5b264a62
BS
6 */
7
8#include <linux/device.h>
9#include <linux/kernel.h>
10#include <linux/i2c.h>
11#include <linux/slab.h>
99c97852 12#include <linux/module.h>
5b264a62 13
06458e27 14#include <linux/iio/iio.h>
5b264a62
BS
15#include "ade7854.h"
16
e4c771d3
RS
17static int ade7854_i2c_write_reg(struct device *dev,
18 u16 reg_address,
19 u32 val,
20 int bits)
5b264a62
BS
21{
22 int ret;
e4c771d3 23 int count;
196b59c1 24 struct iio_dev *indio_dev = dev_to_iio_dev(dev);
937a9601 25 struct ade7854_state *st = iio_priv(indio_dev);
5b264a62
BS
26
27 mutex_lock(&st->buf_lock);
28 st->tx[0] = (reg_address >> 8) & 0xFF;
29 st->tx[1] = reg_address & 0xFF;
5b264a62 30
e4c771d3
RS
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
61unlock:
5b264a62
BS
62 mutex_unlock(&st->buf_lock);
63
4297b23d 64 return ret < 0 ? ret : 0;
5b264a62
BS
65}
66
5d55dcbc
RS
67static int ade7854_i2c_read_reg(struct device *dev,
68 u16 reg_address,
69 u32 *val,
70 int bits)
5b264a62 71{
196b59c1 72 struct iio_dev *indio_dev = dev_to_iio_dev(dev);
937a9601 73 struct ade7854_state *st = iio_priv(indio_dev);
5b264a62
BS
74 int ret;
75
76 mutex_lock(&st->buf_lock);
77 st->tx[0] = (reg_address >> 8) & 0xFF;
78 st->tx[1] = reg_address & 0xFF;
79
80 ret = i2c_master_send(st->i2c, st->tx, 2);
4297b23d 81 if (ret < 0)
5d55dcbc 82 goto unlock;
5b264a62 83
5d55dcbc 84 ret = i2c_master_recv(st->i2c, st->rx, bits);
4297b23d 85 if (ret < 0)
5d55dcbc
RS
86 goto unlock;
87
88 switch (bits) {
89 case 8:
90 *val = st->rx[0];
91 break;
92 case 16:
93 *val = (st->rx[0] << 8) | st->rx[1];
94 break;
95 case 24:
96 *val = (st->rx[0] << 16) | (st->rx[1] << 8) | st->rx[2];
97 break;
98 case 32:
99 *val = (st->rx[0] << 24) | (st->rx[1] << 16) |
100 (st->rx[2] << 8) | st->rx[3];
101 break;
102 default:
103 ret = -EINVAL;
104 goto unlock;
105 }
5b264a62 106
5d55dcbc 107unlock:
5b264a62
BS
108 mutex_unlock(&st->buf_lock);
109 return ret;
110}
111
4ae1c61f 112static int ade7854_i2c_probe(struct i2c_client *client,
08c95f9a 113 const struct i2c_device_id *id)
5b264a62 114{
937a9601
JC
115 struct ade7854_state *st;
116 struct iio_dev *indio_dev;
117
b909459f 118 indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*st));
f9be1085 119 if (!indio_dev)
937a9601
JC
120 return -ENOMEM;
121 st = iio_priv(indio_dev);
122 i2c_set_clientdata(client, indio_dev);
8ea0fa7c 123 st->read_reg = ade7854_i2c_read_reg;
259a8202 124 st->write_reg = ade7854_i2c_write_reg;
5b264a62
BS
125 st->i2c = client;
126 st->irq = client->irq;
127
07f83131 128 return ade7854_probe(indio_dev, &client->dev);
5b264a62
BS
129}
130
5b264a62
BS
131static const struct i2c_device_id ade7854_id[] = {
132 { "ade7854", 0 },
133 { "ade7858", 0 },
134 { "ade7868", 0 },
135 { "ade7878", 0 },
136 { }
137};
138MODULE_DEVICE_TABLE(i2c, ade7854_id);
139
140static struct i2c_driver ade7854_i2c_driver = {
141 .driver = {
142 .name = "ade7854",
143 },
144 .probe = ade7854_i2c_probe,
5b264a62
BS
145 .id_table = ade7854_id,
146};
6e5af184 147module_i2c_driver(ade7854_i2c_driver);
5b264a62
BS
148
149MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
150MODULE_DESCRIPTION("Analog Devices ADE7854/58/68/78 Polyphase Multifunction Energy Metering IC I2C Driver");
151MODULE_LICENSE("GPL v2");