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