linux/drivers/staging/iio/meter/ade7854-i2c.c
<<
>>
Prefs
   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");
 152