Merge branch 'fbdev-next' of git://github.com/schandinat/linux-2.6
[deliverable/linux.git] / drivers / staging / iio / gyro / adis16130_core.c
CommitLineData
7a83f60d
BS
1/*
2 * ADIS16130 Digital Output, High Precision Angular Rate Sensor driver
3 *
4 * Copyright 2010 Analog Devices Inc.
5 *
6 * Licensed under the GPL-2 or later.
7 */
8
7a83f60d
BS
9#include <linux/delay.h>
10#include <linux/mutex.h>
11#include <linux/device.h>
12#include <linux/kernel.h>
13#include <linux/spi/spi.h>
14#include <linux/slab.h>
15#include <linux/sysfs.h>
16#include <linux/list.h>
99c97852 17#include <linux/module.h>
7a83f60d
BS
18
19#include "../iio.h"
20#include "../sysfs.h"
7a83f60d 21
8e678751
JC
22#define ADIS16130_CON 0x0
23#define ADIS16130_CON_RD (1 << 6)
24#define ADIS16130_IOP 0x1
25
26/* 1 = data-ready signal low when unread data on all channels; */
27#define ADIS16130_IOP_ALL_RDY (1 << 3)
28#define ADIS16130_IOP_SYNC (1 << 0) /* 1 = synchronization enabled */
29#define ADIS16130_RATEDATA 0x8 /* Gyroscope output, rate of rotation */
30#define ADIS16130_TEMPDATA 0xA /* Temperature output */
31#define ADIS16130_RATECS 0x28 /* Gyroscope channel setup */
32#define ADIS16130_RATECS_EN (1 << 3) /* 1 = channel enable; */
33#define ADIS16130_TEMPCS 0x2A /* Temperature channel setup */
34#define ADIS16130_TEMPCS_EN (1 << 3)
35#define ADIS16130_RATECONV 0x30
36#define ADIS16130_TEMPCONV 0x32
37#define ADIS16130_MODE 0x38
38#define ADIS16130_MODE_24BIT (1 << 1) /* 1 = 24-bit resolution; */
39
40/**
41 * struct adis16130_state - device instance specific data
42 * @us: actual spi_device to write data
8e678751
JC
43 * @buf_lock: mutex to protect tx and rx
44 * @buf: unified tx/rx buffer
45 **/
46struct adis16130_state {
47 struct spi_device *us;
8e678751
JC
48 struct mutex buf_lock;
49 u8 buf[4] ____cacheline_aligned;
50};
7a83f60d 51
ae0b4bdd 52static int adis16130_spi_read(struct iio_dev *indio_dev, u8 reg_addr, u32 *val)
7a83f60d
BS
53{
54 int ret;
9f8632d7 55 struct adis16130_state *st = iio_priv(indio_dev);
cdf6e817
JC
56 struct spi_message msg;
57 struct spi_transfer xfer = {
58 .tx_buf = st->buf,
59 .rx_buf = st->buf,
a5e7363c 60 .len = 4,
cdf6e817 61 };
7a83f60d
BS
62
63 mutex_lock(&st->buf_lock);
64
8e678751 65 st->buf[0] = ADIS16130_CON_RD | reg_addr;
cdf6e817
JC
66 st->buf[1] = st->buf[2] = st->buf[3] = 0;
67
cdf6e817
JC
68 spi_message_init(&msg);
69 spi_message_add_tail(&xfer, &msg);
70 ret = spi_sync(st->us, &msg);
a5e7363c 71 ret = spi_read(st->us, st->buf, 4);
7a83f60d 72
a5e7363c
JC
73 if (ret == 0)
74 *val = (st->buf[1] << 16) | (st->buf[2] << 8) | st->buf[3];
7a83f60d
BS
75 mutex_unlock(&st->buf_lock);
76
77 return ret;
78}
79
ae0b4bdd
JC
80static int adis16130_read_raw(struct iio_dev *indio_dev,
81 struct iio_chan_spec const *chan,
82 int *val, int *val2,
83 long mask)
7a83f60d 84{
ae0b4bdd
JC
85 int ret;
86 u32 temp;
7a83f60d
BS
87
88 /* Take the iio_dev status lock */
89 mutex_lock(&indio_dev->mlock);
ae0b4bdd 90 ret = adis16130_spi_read(indio_dev, chan->address, &temp);
7a83f60d 91 mutex_unlock(&indio_dev->mlock);
ae0b4bdd 92 if (ret)
7a83f60d 93 return ret;
ae0b4bdd
JC
94 *val = temp;
95 return IIO_VAL_INT;
7a83f60d
BS
96}
97
ae0b4bdd
JC
98static const struct iio_chan_spec adis16130_channels[] = {
99 {
41ea040c 100 .type = IIO_ANGL_VEL,
ae0b4bdd
JC
101 .modified = 1,
102 .channel2 = IIO_MOD_Z,
103 .address = ADIS16130_RATEDATA,
104 }, {
105 .type = IIO_TEMP,
106 .indexed = 1,
107 .channel = 0,
108 .address = ADIS16130_TEMPDATA,
109 }
7a83f60d
BS
110};
111
6fe8135f 112static const struct iio_info adis16130_info = {
ae0b4bdd 113 .read_raw = &adis16130_read_raw,
6fe8135f
JC
114 .driver_module = THIS_MODULE,
115};
116
7a83f60d
BS
117static int __devinit adis16130_probe(struct spi_device *spi)
118{
7a9f437a 119 int ret;
9f8632d7
JC
120 struct adis16130_state *st;
121 struct iio_dev *indio_dev;
122
123 /* setup the industrialio driver allocated elements */
124 indio_dev = iio_allocate_device(sizeof(*st));
125 if (indio_dev == NULL) {
126 ret = -ENOMEM;
7a83f60d
BS
127 goto error_ret;
128 }
9f8632d7 129 st = iio_priv(indio_dev);
7a83f60d 130 /* this is only used for removal purposes */
9f8632d7 131 spi_set_drvdata(spi, indio_dev);
7a83f60d
BS
132 st->us = spi;
133 mutex_init(&st->buf_lock);
9f8632d7 134 indio_dev->name = spi->dev.driver->name;
ae0b4bdd
JC
135 indio_dev->channels = adis16130_channels;
136 indio_dev->num_channels = ARRAY_SIZE(adis16130_channels);
9f8632d7
JC
137 indio_dev->dev.parent = &spi->dev;
138 indio_dev->info = &adis16130_info;
139 indio_dev->modes = INDIO_DIRECT_MODE;
7a83f60d 140
9f8632d7 141 ret = iio_device_register(indio_dev);
7a83f60d 142 if (ret)
7a9f437a 143 goto error_free_dev;
7a83f60d 144
7a83f60d
BS
145 return 0;
146
7a83f60d 147error_free_dev:
9f8632d7
JC
148 iio_free_device(indio_dev);
149
7a83f60d
BS
150error_ret:
151 return ret;
152}
153
154/* fixme, confirm ordering in this function */
155static int adis16130_remove(struct spi_device *spi)
156{
9f8632d7 157 iio_device_unregister(spi_get_drvdata(spi));
d2fffd6c 158 iio_free_device(spi_get_drvdata(spi));
7a83f60d
BS
159
160 return 0;
161}
162
163static struct spi_driver adis16130_driver = {
164 .driver = {
165 .name = "adis16130",
166 .owner = THIS_MODULE,
167 },
168 .probe = adis16130_probe,
169 .remove = __devexit_p(adis16130_remove),
170};
ae6ae6fe 171module_spi_driver(adis16130_driver);
7a83f60d
BS
172
173MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
8e678751 174MODULE_DESCRIPTION("Analog Devices ADIS16130 High Precision Angular Rate");
7a83f60d 175MODULE_LICENSE("GPL v2");
55e4390c 176MODULE_ALIAS("spi:adis16130");
This page took 0.155496 seconds and 5 git commands to generate.