Commit | Line | Data |
---|---|---|
8a27a023 MH |
1 | /* |
2 | * ADE7758 Poly Phase Multifunction Energy Metering IC driver | |
3 | * | |
4 | * Copyright 2010-2011 Analog Devices Inc. | |
5 | * | |
6 | * Licensed under the GPL-2. | |
7 | */ | |
8210cfe9 | 8 | #include <linux/interrupt.h> |
8210cfe9 BS |
9 | #include <linux/kernel.h> |
10 | #include <linux/spi/spi.h> | |
11 | #include <linux/slab.h> | |
8a27a023 | 12 | #include <asm/unaligned.h> |
8210cfe9 BS |
13 | |
14 | #include "../iio.h" | |
8210cfe9 | 15 | #include "../ring_sw.h" |
3f72395e | 16 | #include "../trigger_consumer.h" |
8210cfe9 BS |
17 | #include "ade7758.h" |
18 | ||
19 | /** | |
8a27a023 | 20 | * ade7758_spi_read_burst() - read data registers |
8210cfe9 | 21 | * @dev: device associated with child of actual device (iio_dev or iio_trig) |
8210cfe9 | 22 | **/ |
8a27a023 | 23 | static int ade7758_spi_read_burst(struct device *dev) |
8210cfe9 | 24 | { |
8210cfe9 | 25 | struct iio_dev *indio_dev = dev_get_drvdata(dev); |
a3f02370 | 26 | struct ade7758_state *st = iio_priv(indio_dev); |
8210cfe9 BS |
27 | int ret; |
28 | ||
8a27a023 | 29 | ret = spi_sync(st->us, &st->ring_msg); |
8210cfe9 BS |
30 | if (ret) |
31 | dev_err(&st->us->dev, "problem when reading WFORM value\n"); | |
32 | ||
8a27a023 MH |
33 | return ret; |
34 | } | |
35 | ||
36 | static int ade7758_write_waveform_type(struct device *dev, unsigned type) | |
37 | { | |
38 | int ret; | |
39 | u8 reg; | |
40 | ||
41 | ret = ade7758_spi_read_reg_8(dev, | |
42 | ADE7758_WAVMODE, | |
43 | ®); | |
44 | if (ret) | |
45 | goto out; | |
46 | ||
47 | reg &= ~0x1F; | |
48 | reg |= type & 0x1F; | |
8210cfe9 | 49 | |
8a27a023 MH |
50 | ret = ade7758_spi_write_reg_8(dev, |
51 | ADE7758_WAVMODE, | |
52 | reg); | |
53 | out: | |
8210cfe9 BS |
54 | return ret; |
55 | } | |
56 | ||
57 | /* Whilst this makes a lot of calls to iio_sw_ring functions - it is to device | |
58 | * specific to be rolled into the core. | |
59 | */ | |
3f00ca47 | 60 | static irqreturn_t ade7758_trigger_handler(int irq, void *p) |
8210cfe9 | 61 | { |
3f00ca47 | 62 | struct iio_poll_func *pf = p; |
e65bc6ac | 63 | struct iio_dev *indio_dev = pf->indio_dev; |
3f00ca47 | 64 | struct iio_ring_buffer *ring = indio_dev->ring; |
a3f02370 | 65 | struct ade7758_state *st = iio_priv(indio_dev); |
8a27a023 MH |
66 | s64 dat64[2]; |
67 | u32 *dat32 = (u32 *)dat64; | |
8210cfe9 BS |
68 | |
69 | if (ring->scan_count) | |
a3f02370 | 70 | if (ade7758_spi_read_burst(&indio_dev->dev) >= 0) |
8a27a023 | 71 | *dat32 = get_unaligned_be32(&st->rx_buf[5]) & 0xFFFFFF; |
8210cfe9 BS |
72 | |
73 | /* Guaranteed to be aligned with 8 byte boundary */ | |
74 | if (ring->scan_timestamp) | |
8a27a023 | 75 | dat64[1] = pf->timestamp; |
8210cfe9 | 76 | |
5565a450 | 77 | ring->access->store_to(ring, (u8 *)dat64, pf->timestamp); |
8210cfe9 | 78 | |
a3f02370 | 79 | iio_trigger_notify_done(indio_dev->trig); |
8210cfe9 | 80 | |
3f00ca47 | 81 | return IRQ_HANDLED; |
8210cfe9 BS |
82 | } |
83 | ||
8a27a023 MH |
84 | /** |
85 | * ade7758_ring_preenable() setup the parameters of the ring before enabling | |
86 | * | |
87 | * The complex nature of the setting of the nuber of bytes per datum is due | |
88 | * to this driver currently ensuring that the timestamp is stored at an 8 | |
89 | * byte boundary. | |
90 | **/ | |
91 | static int ade7758_ring_preenable(struct iio_dev *indio_dev) | |
92 | { | |
a3f02370 | 93 | struct ade7758_state *st = iio_priv(indio_dev); |
8a27a023 MH |
94 | struct iio_ring_buffer *ring = indio_dev->ring; |
95 | size_t d_size; | |
96 | unsigned channel; | |
97 | ||
98 | if (!ring->scan_count) | |
99 | return -EINVAL; | |
100 | ||
101 | channel = __ffs(ring->scan_mask); | |
102 | ||
103 | d_size = st->ade7758_ring_channels[channel].scan_type.storagebits / 8; | |
104 | ||
105 | if (ring->scan_timestamp) { | |
106 | d_size += sizeof(s64); | |
107 | ||
108 | if (d_size % sizeof(s64)) | |
109 | d_size += sizeof(s64) - (d_size % sizeof(s64)); | |
110 | } | |
111 | ||
5565a450 JC |
112 | if (indio_dev->ring->access->set_bytes_per_datum) |
113 | indio_dev->ring->access->set_bytes_per_datum(indio_dev->ring, | |
8a27a023 MH |
114 | d_size); |
115 | ||
116 | ade7758_write_waveform_type(&indio_dev->dev, | |
117 | st->ade7758_ring_channels[channel].address); | |
118 | ||
119 | return 0; | |
120 | } | |
121 | ||
5565a450 JC |
122 | static const struct iio_ring_setup_ops ade7758_ring_setup_ops = { |
123 | .preenable = &ade7758_ring_preenable, | |
124 | .postenable = &iio_triggered_ring_postenable, | |
125 | .predisable = &iio_triggered_ring_predisable, | |
126 | }; | |
127 | ||
8210cfe9 BS |
128 | void ade7758_unconfigure_ring(struct iio_dev *indio_dev) |
129 | { | |
0ed731d2 | 130 | iio_dealloc_pollfunc(indio_dev->pollfunc); |
8210cfe9 BS |
131 | iio_sw_rb_free(indio_dev->ring); |
132 | } | |
133 | ||
134 | int ade7758_configure_ring(struct iio_dev *indio_dev) | |
135 | { | |
a3f02370 | 136 | struct ade7758_state *st = iio_priv(indio_dev); |
8210cfe9 | 137 | int ret = 0; |
8210cfe9 | 138 | |
8a27a023 MH |
139 | indio_dev->ring = iio_sw_rb_allocate(indio_dev); |
140 | if (!indio_dev->ring) { | |
8210cfe9 BS |
141 | ret = -ENOMEM; |
142 | return ret; | |
143 | } | |
8a27a023 | 144 | |
8210cfe9 | 145 | /* Effectively select the ring buffer implementation */ |
5565a450 JC |
146 | indio_dev->ring->access = &ring_sw_access_funcs; |
147 | indio_dev->ring->setup_ops = &ade7758_ring_setup_ops; | |
8a27a023 | 148 | indio_dev->ring->owner = THIS_MODULE; |
8210cfe9 | 149 | |
0ed731d2 JC |
150 | indio_dev->pollfunc = iio_alloc_pollfunc(&iio_pollfunc_store_time, |
151 | &ade7758_trigger_handler, | |
152 | 0, | |
153 | indio_dev, | |
154 | "ade7759_consumer%d", | |
155 | indio_dev->id); | |
3f00ca47 JC |
156 | if (indio_dev->pollfunc == NULL) { |
157 | ret = -ENOMEM; | |
8210cfe9 | 158 | goto error_iio_sw_rb_free; |
3f00ca47 | 159 | } |
0ed731d2 | 160 | |
8210cfe9 | 161 | indio_dev->modes |= INDIO_RING_TRIGGERED; |
3f00ca47 | 162 | |
8a27a023 MH |
163 | st->tx_buf[0] = ADE7758_READ_REG(ADE7758_RSTATUS); |
164 | st->tx_buf[1] = 0; | |
165 | st->tx_buf[2] = 0; | |
166 | st->tx_buf[3] = 0; | |
167 | st->tx_buf[4] = ADE7758_READ_REG(ADE7758_WFORM); | |
168 | st->tx_buf[5] = 0; | |
169 | st->tx_buf[6] = 0; | |
170 | st->tx_buf[7] = 0; | |
171 | ||
172 | /* build spi ring message */ | |
173 | st->ring_xfer[0].tx_buf = &st->tx_buf[0]; | |
174 | st->ring_xfer[0].len = 1; | |
175 | st->ring_xfer[0].bits_per_word = 8; | |
176 | st->ring_xfer[0].delay_usecs = 4; | |
177 | st->ring_xfer[1].rx_buf = &st->rx_buf[1]; | |
178 | st->ring_xfer[1].len = 3; | |
179 | st->ring_xfer[1].bits_per_word = 8; | |
180 | st->ring_xfer[1].cs_change = 1; | |
181 | ||
182 | st->ring_xfer[2].tx_buf = &st->tx_buf[4]; | |
183 | st->ring_xfer[2].len = 1; | |
184 | st->ring_xfer[2].bits_per_word = 8; | |
185 | st->ring_xfer[2].delay_usecs = 1; | |
186 | st->ring_xfer[3].rx_buf = &st->rx_buf[5]; | |
187 | st->ring_xfer[3].len = 3; | |
188 | st->ring_xfer[3].bits_per_word = 8; | |
189 | ||
190 | spi_message_init(&st->ring_msg); | |
191 | spi_message_add_tail(&st->ring_xfer[0], &st->ring_msg); | |
192 | spi_message_add_tail(&st->ring_xfer[1], &st->ring_msg); | |
193 | spi_message_add_tail(&st->ring_xfer[2], &st->ring_msg); | |
194 | spi_message_add_tail(&st->ring_xfer[3], &st->ring_msg); | |
195 | ||
8210cfe9 BS |
196 | return 0; |
197 | ||
198 | error_iio_sw_rb_free: | |
199 | iio_sw_rb_free(indio_dev->ring); | |
200 | return ret; | |
201 | } | |
202 | ||
1aa04278 | 203 | void ade7758_uninitialize_ring(struct iio_dev *indio_dev) |
8210cfe9 | 204 | { |
1aa04278 | 205 | iio_ring_buffer_unregister(indio_dev); |
8210cfe9 | 206 | } |