ade7854-i2c.c (3178B)
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 17static 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 61unlock: 62 mutex_unlock(&st->buf_lock); 63 64 return ret < 0 ? ret : 0; 65} 66 67static int ade7854_i2c_read_reg(struct device *dev, 68 u16 reg_address, 69 u32 *val, 70 int bits) 71{ 72 struct iio_dev *indio_dev = dev_to_iio_dev(dev); 73 struct ade7854_state *st = iio_priv(indio_dev); 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); 81 if (ret < 0) 82 goto unlock; 83 84 ret = i2c_master_recv(st->i2c, st->rx, bits); 85 if (ret < 0) 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 } 106 107unlock: 108 mutex_unlock(&st->buf_lock); 109 return ret; 110} 111 112static int ade7854_i2c_probe(struct i2c_client *client, 113 const struct i2c_device_id *id) 114{ 115 struct ade7854_state *st; 116 struct iio_dev *indio_dev; 117 118 indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*st)); 119 if (!indio_dev) 120 return -ENOMEM; 121 st = iio_priv(indio_dev); 122 i2c_set_clientdata(client, indio_dev); 123 st->read_reg = ade7854_i2c_read_reg; 124 st->write_reg = ade7854_i2c_write_reg; 125 st->i2c = client; 126 st->irq = client->irq; 127 128 return ade7854_probe(indio_dev, &client->dev); 129} 130 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, 145 .id_table = ade7854_id, 146}; 147module_i2c_driver(ade7854_i2c_driver); 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");