• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6/drivers/staging/iio/accel/
1#include <linux/interrupt.h>
2#include <linux/irq.h>
3#include <linux/gpio.h>
4#include <linux/workqueue.h>
5#include <linux/mutex.h>
6#include <linux/device.h>
7#include <linux/kernel.h>
8#include <linux/spi/spi.h>
9#include <linux/slab.h>
10#include <linux/sysfs.h>
11#include <linux/list.h>
12
13#include "../iio.h"
14#include "../sysfs.h"
15#include "../ring_sw.h"
16#include "accel.h"
17#include "../trigger.h"
18#include "adis16209.h"
19
20static IIO_SCAN_EL_C(supply, ADIS16209_SCAN_SUPPLY, IIO_UNSIGNED(14),
21		     ADIS16209_SUPPLY_OUT, NULL);
22static IIO_SCAN_EL_C(accel_x, ADIS16209_SCAN_ACC_X, IIO_SIGNED(14),
23		     ADIS16209_XACCL_OUT, NULL);
24static IIO_SCAN_EL_C(accel_y, ADIS16209_SCAN_ACC_Y, IIO_SIGNED(14),
25		     ADIS16209_YACCL_OUT, NULL);
26static IIO_SCAN_EL_C(aux_adc, ADIS16209_SCAN_AUX_ADC, IIO_UNSIGNED(12),
27		     ADIS16209_AUX_ADC, NULL);
28static IIO_SCAN_EL_C(temp, ADIS16209_SCAN_TEMP, IIO_UNSIGNED(12),
29		     ADIS16209_TEMP_OUT, NULL);
30static IIO_SCAN_EL_C(incli_x, ADIS16209_SCAN_INCLI_X, IIO_SIGNED(14),
31		     ADIS16209_XINCL_OUT, NULL);
32static IIO_SCAN_EL_C(incli_y, ADIS16209_SCAN_INCLI_Y, IIO_SIGNED(14),
33		     ADIS16209_YINCL_OUT, NULL);
34static IIO_SCAN_EL_C(rot, ADIS16209_SCAN_ROT, IIO_SIGNED(14),
35		     ADIS16209_ROT_OUT, NULL);
36
37static IIO_SCAN_EL_TIMESTAMP(8);
38
39static struct attribute *adis16209_scan_el_attrs[] = {
40	&iio_scan_el_supply.dev_attr.attr,
41	&iio_scan_el_accel_x.dev_attr.attr,
42	&iio_scan_el_accel_y.dev_attr.attr,
43	&iio_scan_el_aux_adc.dev_attr.attr,
44	&iio_scan_el_temp.dev_attr.attr,
45	&iio_scan_el_incli_x.dev_attr.attr,
46	&iio_scan_el_incli_y.dev_attr.attr,
47	&iio_scan_el_rot.dev_attr.attr,
48	&iio_scan_el_timestamp.dev_attr.attr,
49	NULL,
50};
51
52static struct attribute_group adis16209_scan_el_group = {
53	.attrs = adis16209_scan_el_attrs,
54	.name = "scan_elements",
55};
56
57/**
58 * adis16209_poll_func_th() top half interrupt handler called by trigger
59 * @private_data:	iio_dev
60 **/
61static void adis16209_poll_func_th(struct iio_dev *indio_dev, s64 time)
62{
63	struct adis16209_state *st = iio_dev_get_devdata(indio_dev);
64	st->last_timestamp = time;
65	schedule_work(&st->work_trigger_to_ring);
66}
67
68/**
69 * adis16209_read_ring_data() read data registers which will be placed into ring
70 * @dev: device associated with child of actual device (iio_dev or iio_trig)
71 * @rx: somewhere to pass back the value read
72 **/
73static int adis16209_read_ring_data(struct device *dev, u8 *rx)
74{
75	struct spi_message msg;
76	struct iio_dev *indio_dev = dev_get_drvdata(dev);
77	struct adis16209_state *st = iio_dev_get_devdata(indio_dev);
78	struct spi_transfer xfers[ADIS16209_OUTPUTS + 1];
79	int ret;
80	int i;
81
82	mutex_lock(&st->buf_lock);
83
84	spi_message_init(&msg);
85
86	memset(xfers, 0, sizeof(xfers));
87	for (i = 0; i <= ADIS16209_OUTPUTS; i++) {
88		xfers[i].bits_per_word = 8;
89		xfers[i].cs_change = 1;
90		xfers[i].len = 2;
91		xfers[i].delay_usecs = 20;
92		xfers[i].tx_buf = st->tx + 2 * i;
93		st->tx[2 * i]
94			= ADIS16209_READ_REG(ADIS16209_SUPPLY_OUT + 2 * i);
95		st->tx[2 * i + 1] = 0;
96		if (i >= 1)
97			xfers[i].rx_buf = rx + 2 * (i - 1);
98		spi_message_add_tail(&xfers[i], &msg);
99	}
100
101	ret = spi_sync(st->us, &msg);
102	if (ret)
103		dev_err(&st->us->dev, "problem when burst reading");
104
105	mutex_unlock(&st->buf_lock);
106
107	return ret;
108}
109
110/* Whilst this makes a lot of calls to iio_sw_ring functions - it is to device
111 * specific to be rolled into the core.
112 */
113static void adis16209_trigger_bh_to_ring(struct work_struct *work_s)
114{
115	struct adis16209_state *st
116		= container_of(work_s, struct adis16209_state,
117			       work_trigger_to_ring);
118
119	int i = 0;
120	s16 *data;
121	size_t datasize = st->indio_dev
122		->ring->access.get_bpd(st->indio_dev->ring);
123
124	data = kmalloc(datasize , GFP_KERNEL);
125	if (data == NULL) {
126		dev_err(&st->us->dev, "memory alloc failed in ring bh");
127		return;
128	}
129
130	if (st->indio_dev->scan_count)
131		if (adis16209_read_ring_data(&st->indio_dev->dev, st->rx) >= 0)
132			for (; i < st->indio_dev->scan_count; i++)
133				data[i] = be16_to_cpup(
134					(__be16 *)&(st->rx[i*2]));
135
136	/* Guaranteed to be aligned with 8 byte boundary */
137	if (st->indio_dev->scan_timestamp)
138		*((s64 *)(data + ((i + 3)/4)*4)) = st->last_timestamp;
139
140	st->indio_dev->ring->access.store_to(st->indio_dev->ring,
141					    (u8 *)data,
142					    st->last_timestamp);
143
144	iio_trigger_notify_done(st->indio_dev->trig);
145	kfree(data);
146
147	return;
148}
149
150void adis16209_unconfigure_ring(struct iio_dev *indio_dev)
151{
152	kfree(indio_dev->pollfunc);
153	iio_sw_rb_free(indio_dev->ring);
154}
155
156int adis16209_configure_ring(struct iio_dev *indio_dev)
157{
158	int ret = 0;
159	struct adis16209_state *st = indio_dev->dev_data;
160	struct iio_ring_buffer *ring;
161	INIT_WORK(&st->work_trigger_to_ring, adis16209_trigger_bh_to_ring);
162	/* Set default scan mode */
163
164	iio_scan_mask_set(indio_dev, iio_scan_el_supply.number);
165	iio_scan_mask_set(indio_dev, iio_scan_el_rot.number);
166	iio_scan_mask_set(indio_dev, iio_scan_el_accel_x.number);
167	iio_scan_mask_set(indio_dev, iio_scan_el_accel_y.number);
168	iio_scan_mask_set(indio_dev, iio_scan_el_temp.number);
169	iio_scan_mask_set(indio_dev, iio_scan_el_aux_adc.number);
170	iio_scan_mask_set(indio_dev, iio_scan_el_incli_x.number);
171	iio_scan_mask_set(indio_dev, iio_scan_el_incli_y.number);
172	indio_dev->scan_timestamp = true;
173
174	indio_dev->scan_el_attrs = &adis16209_scan_el_group;
175
176	ring = iio_sw_rb_allocate(indio_dev);
177	if (!ring) {
178		ret = -ENOMEM;
179		return ret;
180	}
181	indio_dev->ring = ring;
182	/* Effectively select the ring buffer implementation */
183	iio_ring_sw_register_funcs(&ring->access);
184	ring->bpe = 2;
185	ring->preenable = &iio_sw_ring_preenable;
186	ring->postenable = &iio_triggered_ring_postenable;
187	ring->predisable = &iio_triggered_ring_predisable;
188	ring->owner = THIS_MODULE;
189
190	ret = iio_alloc_pollfunc(indio_dev, NULL, &adis16209_poll_func_th);
191	if (ret)
192		goto error_iio_sw_rb_free;
193
194	indio_dev->modes |= INDIO_RING_TRIGGERED;
195	return 0;
196
197error_iio_sw_rb_free:
198	iio_sw_rb_free(indio_dev->ring);
199	return ret;
200}
201