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