aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDenis Ciocca <denis.ciocca@gmail.com>2013-01-25 18:44:00 -0500
committerJonathan Cameron <jic23@kernel.org>2013-01-31 12:56:43 -0500
commit872e79add7561645b130fba63aa7ca12098a9361 (patch)
tree96ecdf425cfc12b4050e7e569cdbb4bcc5bf6715
parent7be56a8f57b57cca1651fb97886e20246c168e25 (diff)
iio:magnetometer: Add STMicroelectronics magnetometers driver
This patch adds a generic magnetometer driver for STMicroelectronics magnetometers, currently it supports: LSM303DLHC, LSM303DLM, LIS3MDL. Signed-off-by: Denis Ciocca <denis.ciocca@st.com> Signed-off-by: Jonathan Cameron <jic23@kernel.org>
-rw-r--r--drivers/iio/magnetometer/Kconfig30
-rw-r--r--drivers/iio/magnetometer/Makefile7
-rw-r--r--drivers/iio/magnetometer/st_magn.h45
-rw-r--r--drivers/iio/magnetometer/st_magn_buffer.c98
-rw-r--r--drivers/iio/magnetometer/st_magn_core.c401
-rw-r--r--drivers/iio/magnetometer/st_magn_i2c.c81
-rw-r--r--drivers/iio/magnetometer/st_magn_spi.c80
7 files changed, 742 insertions, 0 deletions
diff --git a/drivers/iio/magnetometer/Kconfig b/drivers/iio/magnetometer/Kconfig
index ff11d68225cf..cd29be54f643 100644
--- a/drivers/iio/magnetometer/Kconfig
+++ b/drivers/iio/magnetometer/Kconfig
@@ -14,4 +14,34 @@ config HID_SENSOR_MAGNETOMETER_3D
14 Say yes here to build support for the HID SENSOR 14 Say yes here to build support for the HID SENSOR
15 Magnetometer 3D. 15 Magnetometer 3D.
16 16
17config IIO_ST_MAGN_3AXIS
18 tristate "STMicroelectronics magnetometers 3-Axis Driver"
19 depends on (I2C || SPI_MASTER) && SYSFS
20 select IIO_ST_SENSORS_CORE
21 select IIO_ST_MAGN_I2C_3AXIS if (I2C)
22 select IIO_ST_MAGN_SPI_3AXIS if (SPI_MASTER)
23 select IIO_TRIGGERED_BUFFER if (IIO_BUFFER)
24 select IIO_ST_MAGN_BUFFER if (IIO_TRIGGERED_BUFFER)
25 help
26 Say yes here to build support for STMicroelectronics magnetometers:
27 LSM303DLHC, LSM303DLM, LIS3MDL.
28
29 This driver can also be built as a module. If so, will be created
30 these modules:
31 - st_magn (core functions for the driver [it is mandatory]);
32 - st_magn_i2c (necessary for the I2C devices [optional*]);
33 - st_magn_spi (necessary for the SPI devices [optional*]);
34
35 (*) one of these is necessary to do something.
36
37config IIO_ST_MAGN_I2C_3AXIS
38 tristate
39 depends on IIO_ST_MAGN_3AXIS
40 depends on IIO_ST_SENSORS_I2C
41
42config IIO_ST_MAGN_SPI_3AXIS
43 tristate
44 depends on IIO_ST_MAGN_3AXIS
45 depends on IIO_ST_SENSORS_SPI
46
17endmenu 47endmenu
diff --git a/drivers/iio/magnetometer/Makefile b/drivers/iio/magnetometer/Makefile
index 60dc4f2b1963..e78672876dc2 100644
--- a/drivers/iio/magnetometer/Makefile
+++ b/drivers/iio/magnetometer/Makefile
@@ -3,3 +3,10 @@
3# 3#
4 4
5obj-$(CONFIG_HID_SENSOR_MAGNETOMETER_3D) += hid-sensor-magn-3d.o 5obj-$(CONFIG_HID_SENSOR_MAGNETOMETER_3D) += hid-sensor-magn-3d.o
6
7obj-$(CONFIG_IIO_ST_MAGN_3AXIS) += st_magn.o
8st_magn-y := st_magn_core.o
9st_magn-$(CONFIG_IIO_BUFFER) += st_magn_buffer.o
10
11obj-$(CONFIG_IIO_ST_MAGN_I2C_3AXIS) += st_magn_i2c.o
12obj-$(CONFIG_IIO_ST_MAGN_SPI_3AXIS) += st_magn_spi.o
diff --git a/drivers/iio/magnetometer/st_magn.h b/drivers/iio/magnetometer/st_magn.h
new file mode 100644
index 000000000000..7e81d00ef0c3
--- /dev/null
+++ b/drivers/iio/magnetometer/st_magn.h
@@ -0,0 +1,45 @@
1/*
2 * STMicroelectronics magnetometers driver
3 *
4 * Copyright 2012-2013 STMicroelectronics Inc.
5 *
6 * Denis Ciocca <denis.ciocca@st.com>
7 * v. 1.0.0
8 * Licensed under the GPL-2.
9 */
10
11#ifndef ST_MAGN_H
12#define ST_MAGN_H
13
14#include <linux/types.h>
15#include <linux/iio/common/st_sensors.h>
16
17#define LSM303DLHC_MAGN_DEV_NAME "lsm303dlhc_magn"
18#define LSM303DLM_MAGN_DEV_NAME "lsm303dlm_magn"
19#define LIS3MDL_MAGN_DEV_NAME "lis3mdl"
20
21int st_magn_common_probe(struct iio_dev *indio_dev);
22void st_magn_common_remove(struct iio_dev *indio_dev);
23
24#ifdef CONFIG_IIO_BUFFER
25int st_magn_allocate_ring(struct iio_dev *indio_dev);
26void st_magn_deallocate_ring(struct iio_dev *indio_dev);
27#else /* CONFIG_IIO_BUFFER */
28static inline int st_magn_probe_trigger(struct iio_dev *indio_dev, int irq)
29{
30 return 0;
31}
32static inline void st_magn_remove_trigger(struct iio_dev *indio_dev, int irq)
33{
34 return;
35}
36static inline int st_magn_allocate_ring(struct iio_dev *indio_dev)
37{
38 return 0;
39}
40static inline void st_magn_deallocate_ring(struct iio_dev *indio_dev)
41{
42}
43#endif /* CONFIG_IIO_BUFFER */
44
45#endif /* ST_MAGN_H */
diff --git a/drivers/iio/magnetometer/st_magn_buffer.c b/drivers/iio/magnetometer/st_magn_buffer.c
new file mode 100644
index 000000000000..708857bdb47d
--- /dev/null
+++ b/drivers/iio/magnetometer/st_magn_buffer.c
@@ -0,0 +1,98 @@
1/*
2 * STMicroelectronics magnetometers driver
3 *
4 * Copyright 2012-2013 STMicroelectronics Inc.
5 *
6 * Denis Ciocca <denis.ciocca@st.com>
7 *
8 * Licensed under the GPL-2.
9 */
10
11#include <linux/module.h>
12#include <linux/kernel.h>
13#include <linux/slab.h>
14#include <linux/stat.h>
15#include <linux/interrupt.h>
16#include <linux/i2c.h>
17#include <linux/delay.h>
18#include <linux/iio/iio.h>
19#include <linux/iio/buffer.h>
20#include <linux/iio/trigger_consumer.h>
21#include <linux/iio/triggered_buffer.h>
22
23#include <linux/iio/common/st_sensors.h>
24#include "st_magn.h"
25
26static int st_magn_buffer_preenable(struct iio_dev *indio_dev)
27{
28 int err;
29
30 err = st_sensors_set_enable(indio_dev, true);
31 if (err < 0)
32 goto st_magn_set_enable_error;
33
34 err = iio_sw_buffer_preenable(indio_dev);
35
36st_magn_set_enable_error:
37 return err;
38}
39
40static int st_magn_buffer_postenable(struct iio_dev *indio_dev)
41{
42 int err;
43 struct st_sensor_data *mdata = iio_priv(indio_dev);
44
45 mdata->buffer_data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
46 if (mdata->buffer_data == NULL) {
47 err = -ENOMEM;
48 goto allocate_memory_error;
49 }
50
51 err = iio_triggered_buffer_postenable(indio_dev);
52 if (err < 0)
53 goto st_magn_buffer_postenable_error;
54
55 return err;
56
57st_magn_buffer_postenable_error:
58 kfree(mdata->buffer_data);
59allocate_memory_error:
60 return err;
61}
62
63static int st_magn_buffer_predisable(struct iio_dev *indio_dev)
64{
65 int err;
66 struct st_sensor_data *mdata = iio_priv(indio_dev);
67
68 err = iio_triggered_buffer_predisable(indio_dev);
69 if (err < 0)
70 goto st_magn_buffer_predisable_error;
71
72 err = st_sensors_set_enable(indio_dev, false);
73
74st_magn_buffer_predisable_error:
75 kfree(mdata->buffer_data);
76 return err;
77}
78
79static const struct iio_buffer_setup_ops st_magn_buffer_setup_ops = {
80 .preenable = &st_magn_buffer_preenable,
81 .postenable = &st_magn_buffer_postenable,
82 .predisable = &st_magn_buffer_predisable,
83};
84
85int st_magn_allocate_ring(struct iio_dev *indio_dev)
86{
87 return iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
88 &st_sensors_trigger_handler, &st_magn_buffer_setup_ops);
89}
90
91void st_magn_deallocate_ring(struct iio_dev *indio_dev)
92{
93 iio_triggered_buffer_cleanup(indio_dev);
94}
95
96MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
97MODULE_DESCRIPTION("STMicroelectronics magnetometers buffer");
98MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/magnetometer/st_magn_core.c b/drivers/iio/magnetometer/st_magn_core.c
new file mode 100644
index 000000000000..a69fbe19fc8e
--- /dev/null
+++ b/drivers/iio/magnetometer/st_magn_core.c
@@ -0,0 +1,401 @@
1/*
2 * STMicroelectronics magnetometers driver
3 *
4 * Copyright 2012-2013 STMicroelectronics Inc.
5 *
6 * Denis Ciocca <denis.ciocca@st.com>
7 *
8 * Licensed under the GPL-2.
9 */
10
11#include <linux/kernel.h>
12#include <linux/module.h>
13#include <linux/slab.h>
14#include <linux/errno.h>
15#include <linux/types.h>
16#include <linux/mutex.h>
17#include <linux/interrupt.h>
18#include <linux/i2c.h>
19#include <linux/gpio.h>
20#include <linux/irq.h>
21#include <linux/delay.h>
22#include <linux/iio/iio.h>
23#include <linux/iio/sysfs.h>
24#include <linux/iio/trigger_consumer.h>
25#include <linux/iio/buffer.h>
26
27#include <linux/iio/common/st_sensors.h>
28#include "st_magn.h"
29
30/* DEFAULT VALUE FOR SENSORS */
31#define ST_MAGN_DEFAULT_OUT_X_L_ADDR 0X04
32#define ST_MAGN_DEFAULT_OUT_Y_L_ADDR 0X08
33#define ST_MAGN_DEFAULT_OUT_Z_L_ADDR 0X06
34
35/* FULLSCALE */
36#define ST_MAGN_FS_AVL_1300MG 1300
37#define ST_MAGN_FS_AVL_1900MG 1900
38#define ST_MAGN_FS_AVL_2500MG 2500
39#define ST_MAGN_FS_AVL_4000MG 4000
40#define ST_MAGN_FS_AVL_4700MG 4700
41#define ST_MAGN_FS_AVL_5600MG 5600
42#define ST_MAGN_FS_AVL_8000MG 8000
43#define ST_MAGN_FS_AVL_8100MG 8100
44#define ST_MAGN_FS_AVL_10000MG 10000
45
46/* CUSTOM VALUES FOR SENSOR 1 */
47#define ST_MAGN_1_WAI_EXP 0x3c
48#define ST_MAGN_1_ODR_ADDR 0x00
49#define ST_MAGN_1_ODR_MASK 0x1c
50#define ST_MAGN_1_ODR_AVL_1HZ_VAL 0x00
51#define ST_MAGN_1_ODR_AVL_2HZ_VAL 0x01
52#define ST_MAGN_1_ODR_AVL_3HZ_VAL 0x02
53#define ST_MAGN_1_ODR_AVL_8HZ_VAL 0x03
54#define ST_MAGN_1_ODR_AVL_15HZ_VAL 0x04
55#define ST_MAGN_1_ODR_AVL_30HZ_VAL 0x05
56#define ST_MAGN_1_ODR_AVL_75HZ_VAL 0x06
57#define ST_MAGN_1_ODR_AVL_220HZ_VAL 0x07
58#define ST_MAGN_1_PW_ADDR 0x02
59#define ST_MAGN_1_PW_MASK 0x03
60#define ST_MAGN_1_PW_ON 0x00
61#define ST_MAGN_1_PW_OFF 0x03
62#define ST_MAGN_1_FS_ADDR 0x01
63#define ST_MAGN_1_FS_MASK 0xe0
64#define ST_MAGN_1_FS_AVL_1300_VAL 0x01
65#define ST_MAGN_1_FS_AVL_1900_VAL 0x02
66#define ST_MAGN_1_FS_AVL_2500_VAL 0x03
67#define ST_MAGN_1_FS_AVL_4000_VAL 0x04
68#define ST_MAGN_1_FS_AVL_4700_VAL 0x05
69#define ST_MAGN_1_FS_AVL_5600_VAL 0x06
70#define ST_MAGN_1_FS_AVL_8100_VAL 0x07
71#define ST_MAGN_1_FS_AVL_1300_GAIN_XY 1100
72#define ST_MAGN_1_FS_AVL_1900_GAIN_XY 855
73#define ST_MAGN_1_FS_AVL_2500_GAIN_XY 670
74#define ST_MAGN_1_FS_AVL_4000_GAIN_XY 450
75#define ST_MAGN_1_FS_AVL_4700_GAIN_XY 400
76#define ST_MAGN_1_FS_AVL_5600_GAIN_XY 330
77#define ST_MAGN_1_FS_AVL_8100_GAIN_XY 230
78#define ST_MAGN_1_FS_AVL_1300_GAIN_Z 980
79#define ST_MAGN_1_FS_AVL_1900_GAIN_Z 760
80#define ST_MAGN_1_FS_AVL_2500_GAIN_Z 600
81#define ST_MAGN_1_FS_AVL_4000_GAIN_Z 400
82#define ST_MAGN_1_FS_AVL_4700_GAIN_Z 355
83#define ST_MAGN_1_FS_AVL_5600_GAIN_Z 295
84#define ST_MAGN_1_FS_AVL_8100_GAIN_Z 205
85#define ST_MAGN_1_MULTIREAD_BIT false
86
87/* CUSTOM VALUES FOR SENSOR 2 */
88#define ST_MAGN_2_WAI_EXP 0x3d
89#define ST_MAGN_2_ODR_ADDR 0x20
90#define ST_MAGN_2_ODR_MASK 0x1c
91#define ST_MAGN_2_ODR_AVL_1HZ_VAL 0x00
92#define ST_MAGN_2_ODR_AVL_2HZ_VAL 0x01
93#define ST_MAGN_2_ODR_AVL_3HZ_VAL 0x02
94#define ST_MAGN_2_ODR_AVL_5HZ_VAL 0x03
95#define ST_MAGN_2_ODR_AVL_10HZ_VAL 0x04
96#define ST_MAGN_2_ODR_AVL_20HZ_VAL 0x05
97#define ST_MAGN_2_ODR_AVL_40HZ_VAL 0x06
98#define ST_MAGN_2_ODR_AVL_80HZ_VAL 0x07
99#define ST_MAGN_2_PW_ADDR 0x22
100#define ST_MAGN_2_PW_MASK 0x03
101#define ST_MAGN_2_PW_ON 0x00
102#define ST_MAGN_2_PW_OFF 0x03
103#define ST_MAGN_2_FS_ADDR 0x21
104#define ST_MAGN_2_FS_MASK 0x60
105#define ST_MAGN_2_FS_AVL_4000_VAL 0x00
106#define ST_MAGN_2_FS_AVL_8000_VAL 0x01
107#define ST_MAGN_2_FS_AVL_10000_VAL 0x02
108#define ST_MAGN_2_FS_AVL_4000_GAIN 430
109#define ST_MAGN_2_FS_AVL_8000_GAIN 230
110#define ST_MAGN_2_FS_AVL_10000_GAIN 230
111#define ST_MAGN_2_MULTIREAD_BIT false
112#define ST_MAGN_2_OUT_X_L_ADDR 0x28
113#define ST_MAGN_2_OUT_Y_L_ADDR 0x2a
114#define ST_MAGN_2_OUT_Z_L_ADDR 0x2c
115
116static const struct iio_chan_spec st_magn_16bit_channels[] = {
117 ST_SENSORS_LSM_CHANNELS(IIO_MAGN, ST_SENSORS_SCAN_X, IIO_MOD_X, IIO_LE,
118 ST_SENSORS_DEFAULT_16_REALBITS, ST_MAGN_DEFAULT_OUT_X_L_ADDR),
119 ST_SENSORS_LSM_CHANNELS(IIO_MAGN, ST_SENSORS_SCAN_Y, IIO_MOD_Y, IIO_LE,
120 ST_SENSORS_DEFAULT_16_REALBITS, ST_MAGN_DEFAULT_OUT_Y_L_ADDR),
121 ST_SENSORS_LSM_CHANNELS(IIO_MAGN, ST_SENSORS_SCAN_Z, IIO_MOD_Z, IIO_LE,
122 ST_SENSORS_DEFAULT_16_REALBITS, ST_MAGN_DEFAULT_OUT_Z_L_ADDR),
123 IIO_CHAN_SOFT_TIMESTAMP(3)
124};
125
126static const struct iio_chan_spec st_magn_2_16bit_channels[] = {
127 ST_SENSORS_LSM_CHANNELS(IIO_MAGN, ST_SENSORS_SCAN_X, IIO_MOD_X, IIO_LE,
128 ST_SENSORS_DEFAULT_16_REALBITS, ST_MAGN_2_OUT_X_L_ADDR),
129 ST_SENSORS_LSM_CHANNELS(IIO_MAGN, ST_SENSORS_SCAN_Y, IIO_MOD_Y, IIO_LE,
130 ST_SENSORS_DEFAULT_16_REALBITS, ST_MAGN_2_OUT_Y_L_ADDR),
131 ST_SENSORS_LSM_CHANNELS(IIO_MAGN, ST_SENSORS_SCAN_Z, IIO_MOD_Z, IIO_LE,
132 ST_SENSORS_DEFAULT_16_REALBITS, ST_MAGN_2_OUT_Z_L_ADDR),
133 IIO_CHAN_SOFT_TIMESTAMP(3)
134};
135
136static const struct st_sensors st_magn_sensors[] = {
137 {
138 .wai = ST_MAGN_1_WAI_EXP,
139 .sensors_supported = {
140 [0] = LSM303DLHC_MAGN_DEV_NAME,
141 [1] = LSM303DLM_MAGN_DEV_NAME,
142 },
143 .ch = (struct iio_chan_spec *)st_magn_16bit_channels,
144 .odr = {
145 .addr = ST_MAGN_1_ODR_ADDR,
146 .mask = ST_MAGN_1_ODR_MASK,
147 .odr_avl = {
148 { 1, ST_MAGN_1_ODR_AVL_1HZ_VAL, },
149 { 2, ST_MAGN_1_ODR_AVL_2HZ_VAL, },
150 { 3, ST_MAGN_1_ODR_AVL_3HZ_VAL, },
151 { 8, ST_MAGN_1_ODR_AVL_8HZ_VAL, },
152 { 15, ST_MAGN_1_ODR_AVL_15HZ_VAL, },
153 { 30, ST_MAGN_1_ODR_AVL_30HZ_VAL, },
154 { 75, ST_MAGN_1_ODR_AVL_75HZ_VAL, },
155 { 220, ST_MAGN_1_ODR_AVL_220HZ_VAL, },
156 },
157 },
158 .pw = {
159 .addr = ST_MAGN_1_PW_ADDR,
160 .mask = ST_MAGN_1_PW_MASK,
161 .value_on = ST_MAGN_1_PW_ON,
162 .value_off = ST_MAGN_1_PW_OFF,
163 },
164 .fs = {
165 .addr = ST_MAGN_1_FS_ADDR,
166 .mask = ST_MAGN_1_FS_MASK,
167 .fs_avl = {
168 [0] = {
169 .num = ST_MAGN_FS_AVL_1300MG,
170 .value = ST_MAGN_1_FS_AVL_1300_VAL,
171 .gain = ST_MAGN_1_FS_AVL_1300_GAIN_XY,
172 .gain2 = ST_MAGN_1_FS_AVL_1300_GAIN_Z,
173 },
174 [1] = {
175 .num = ST_MAGN_FS_AVL_1900MG,
176 .value = ST_MAGN_1_FS_AVL_1900_VAL,
177 .gain = ST_MAGN_1_FS_AVL_1900_GAIN_XY,
178 .gain2 = ST_MAGN_1_FS_AVL_1900_GAIN_Z,
179 },
180 [2] = {
181 .num = ST_MAGN_FS_AVL_2500MG,
182 .value = ST_MAGN_1_FS_AVL_2500_VAL,
183 .gain = ST_MAGN_1_FS_AVL_2500_GAIN_XY,
184 .gain2 = ST_MAGN_1_FS_AVL_2500_GAIN_Z,
185 },
186 [3] = {
187 .num = ST_MAGN_FS_AVL_4000MG,
188 .value = ST_MAGN_1_FS_AVL_4000_VAL,
189 .gain = ST_MAGN_1_FS_AVL_4000_GAIN_XY,
190 .gain2 = ST_MAGN_1_FS_AVL_4000_GAIN_Z,
191 },
192 [4] = {
193 .num = ST_MAGN_FS_AVL_4700MG,
194 .value = ST_MAGN_1_FS_AVL_4700_VAL,
195 .gain = ST_MAGN_1_FS_AVL_4700_GAIN_XY,
196 .gain2 = ST_MAGN_1_FS_AVL_4700_GAIN_Z,
197 },
198 [5] = {
199 .num = ST_MAGN_FS_AVL_5600MG,
200 .value = ST_MAGN_1_FS_AVL_5600_VAL,
201 .gain = ST_MAGN_1_FS_AVL_5600_GAIN_XY,
202 .gain2 = ST_MAGN_1_FS_AVL_5600_GAIN_Z,
203 },
204 [6] = {
205 .num = ST_MAGN_FS_AVL_8100MG,
206 .value = ST_MAGN_1_FS_AVL_8100_VAL,
207 .gain = ST_MAGN_1_FS_AVL_8100_GAIN_XY,
208 .gain2 = ST_MAGN_1_FS_AVL_8100_GAIN_Z,
209 },
210 },
211 },
212 .multi_read_bit = ST_MAGN_1_MULTIREAD_BIT,
213 .bootime = 2,
214 },
215 {
216 .wai = ST_MAGN_2_WAI_EXP,
217 .sensors_supported = {
218 [0] = LIS3MDL_MAGN_DEV_NAME,
219 },
220 .ch = (struct iio_chan_spec *)st_magn_2_16bit_channels,
221 .odr = {
222 .addr = ST_MAGN_2_ODR_ADDR,
223 .mask = ST_MAGN_2_ODR_MASK,
224 .odr_avl = {
225 { 1, ST_MAGN_2_ODR_AVL_1HZ_VAL, },
226 { 2, ST_MAGN_2_ODR_AVL_2HZ_VAL, },
227 { 3, ST_MAGN_2_ODR_AVL_3HZ_VAL, },
228 { 5, ST_MAGN_2_ODR_AVL_5HZ_VAL, },
229 { 10, ST_MAGN_2_ODR_AVL_10HZ_VAL, },
230 { 20, ST_MAGN_2_ODR_AVL_20HZ_VAL, },
231 { 40, ST_MAGN_2_ODR_AVL_40HZ_VAL, },
232 { 80, ST_MAGN_2_ODR_AVL_80HZ_VAL, },
233 },
234 },
235 .pw = {
236 .addr = ST_MAGN_2_PW_ADDR,
237 .mask = ST_MAGN_2_PW_MASK,
238 .value_on = ST_MAGN_2_PW_ON,
239 .value_off = ST_MAGN_2_PW_OFF,
240 },
241 .fs = {
242 .addr = ST_MAGN_2_FS_ADDR,
243 .mask = ST_MAGN_2_FS_MASK,
244 .fs_avl = {
245 [0] = {
246 .num = ST_MAGN_FS_AVL_4000MG,
247 .value = ST_MAGN_2_FS_AVL_4000_VAL,
248 .gain = ST_MAGN_2_FS_AVL_4000_GAIN,
249 },
250 [1] = {
251 .num = ST_MAGN_FS_AVL_8000MG,
252 .value = ST_MAGN_2_FS_AVL_8000_VAL,
253 .gain = ST_MAGN_2_FS_AVL_8000_GAIN,
254 },
255 [2] = {
256 .num = ST_MAGN_FS_AVL_10000MG,
257 .value = ST_MAGN_2_FS_AVL_10000_VAL,
258 .gain = ST_MAGN_2_FS_AVL_10000_GAIN,
259 },
260 },
261 },
262 .multi_read_bit = ST_MAGN_2_MULTIREAD_BIT,
263 .bootime = 2,
264 },
265};
266
267static int st_magn_read_raw(struct iio_dev *indio_dev,
268 struct iio_chan_spec const *ch, int *val,
269 int *val2, long mask)
270{
271 int err;
272 struct st_sensor_data *mdata = iio_priv(indio_dev);
273
274 switch (mask) {
275 case IIO_CHAN_INFO_RAW:
276 err = st_sensors_read_info_raw(indio_dev, ch, val);
277 if (err < 0)
278 goto read_error;
279
280 return IIO_VAL_INT;
281 case IIO_CHAN_INFO_SCALE:
282 *val = 0;
283 if ((ch->scan_index == ST_SENSORS_SCAN_Z) &&
284 (mdata->current_fullscale->gain2 != 0))
285 *val2 = mdata->current_fullscale->gain2;
286 else
287 *val2 = mdata->current_fullscale->gain;
288 return IIO_VAL_INT_PLUS_MICRO;
289 default:
290 return -EINVAL;
291 }
292
293read_error:
294 return err;
295}
296
297static int st_magn_write_raw(struct iio_dev *indio_dev,
298 struct iio_chan_spec const *chan, int val, int val2, long mask)
299{
300 int err;
301
302 switch (mask) {
303 case IIO_CHAN_INFO_SCALE:
304 err = st_sensors_set_fullscale_by_gain(indio_dev, val2);
305 break;
306 default:
307 err = -EINVAL;
308 }
309
310 return err;
311}
312
313static ST_SENSOR_DEV_ATTR_SAMP_FREQ();
314static ST_SENSORS_DEV_ATTR_SAMP_FREQ_AVAIL();
315static ST_SENSORS_DEV_ATTR_SCALE_AVAIL(in_magn_scale_available);
316
317static struct attribute *st_magn_attributes[] = {
318 &iio_dev_attr_sampling_frequency_available.dev_attr.attr,
319 &iio_dev_attr_in_magn_scale_available.dev_attr.attr,
320 &iio_dev_attr_sampling_frequency.dev_attr.attr,
321 NULL,
322};
323
324static const struct attribute_group st_magn_attribute_group = {
325 .attrs = st_magn_attributes,
326};
327
328static const struct iio_info magn_info = {
329 .driver_module = THIS_MODULE,
330 .attrs = &st_magn_attribute_group,
331 .read_raw = &st_magn_read_raw,
332 .write_raw = &st_magn_write_raw,
333};
334
335int st_magn_common_probe(struct iio_dev *indio_dev)
336{
337 int err;
338 struct st_sensor_data *mdata = iio_priv(indio_dev);
339
340 indio_dev->modes = INDIO_DIRECT_MODE;
341 indio_dev->info = &magn_info;
342
343 err = st_sensors_check_device_support(indio_dev,
344 ARRAY_SIZE(st_magn_sensors), st_magn_sensors);
345 if (err < 0)
346 goto st_magn_common_probe_error;
347
348 mdata->multiread_bit = mdata->sensor->multi_read_bit;
349 indio_dev->channels = mdata->sensor->ch;
350 indio_dev->num_channels = ST_SENSORS_NUMBER_ALL_CHANNELS;
351
352 mdata->current_fullscale = (struct st_sensor_fullscale_avl *)
353 &mdata->sensor->fs.fs_avl[0];
354 mdata->odr = mdata->sensor->odr.odr_avl[0].hz;
355
356 err = st_sensors_init_sensor(indio_dev);
357 if (err < 0)
358 goto st_magn_common_probe_error;
359
360 if (mdata->get_irq_data_ready(indio_dev) > 0) {
361 err = st_magn_allocate_ring(indio_dev);
362 if (err < 0)
363 goto st_magn_common_probe_error;
364 err = st_sensors_allocate_trigger(indio_dev, NULL);
365 if (err < 0)
366 goto st_magn_probe_trigger_error;
367 }
368
369 err = iio_device_register(indio_dev);
370 if (err)
371 goto st_magn_device_register_error;
372
373 return err;
374
375st_magn_device_register_error:
376 if (mdata->get_irq_data_ready(indio_dev) > 0)
377 st_sensors_deallocate_trigger(indio_dev);
378st_magn_probe_trigger_error:
379 if (mdata->get_irq_data_ready(indio_dev) > 0)
380 st_magn_deallocate_ring(indio_dev);
381st_magn_common_probe_error:
382 return err;
383}
384EXPORT_SYMBOL(st_magn_common_probe);
385
386void st_magn_common_remove(struct iio_dev *indio_dev)
387{
388 struct st_sensor_data *mdata = iio_priv(indio_dev);
389
390 iio_device_unregister(indio_dev);
391 if (mdata->get_irq_data_ready(indio_dev) > 0) {
392 st_sensors_deallocate_trigger(indio_dev);
393 st_magn_deallocate_ring(indio_dev);
394 }
395 iio_device_free(indio_dev);
396}
397EXPORT_SYMBOL(st_magn_common_remove);
398
399MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
400MODULE_DESCRIPTION("STMicroelectronics magnetometers driver");
401MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/magnetometer/st_magn_i2c.c b/drivers/iio/magnetometer/st_magn_i2c.c
new file mode 100644
index 000000000000..710b256a5a0e
--- /dev/null
+++ b/drivers/iio/magnetometer/st_magn_i2c.c
@@ -0,0 +1,81 @@
1/*
2 * STMicroelectronics magnetometers driver
3 *
4 * Copyright 2012-2013 STMicroelectronics Inc.
5 *
6 * Denis Ciocca <denis.ciocca@st.com>
7 *
8 * Licensed under the GPL-2.
9 */
10
11#include <linux/kernel.h>
12#include <linux/module.h>
13#include <linux/slab.h>
14#include <linux/i2c.h>
15#include <linux/iio/iio.h>
16#include <linux/iio/trigger.h>
17
18#include <linux/iio/common/st_sensors.h>
19#include <linux/iio/common/st_sensors_i2c.h>
20#include "st_magn.h"
21
22static int st_magn_i2c_probe(struct i2c_client *client,
23 const struct i2c_device_id *id)
24{
25 struct iio_dev *indio_dev;
26 struct st_sensor_data *mdata;
27 int err;
28
29 indio_dev = iio_device_alloc(sizeof(*mdata));
30 if (indio_dev == NULL) {
31 err = -ENOMEM;
32 goto iio_device_alloc_error;
33 }
34
35 mdata = iio_priv(indio_dev);
36 mdata->dev = &client->dev;
37
38 st_sensors_i2c_configure(indio_dev, client, mdata);
39
40 err = st_magn_common_probe(indio_dev);
41 if (err < 0)
42 goto st_magn_common_probe_error;
43
44 return 0;
45
46st_magn_common_probe_error:
47 iio_device_free(indio_dev);
48iio_device_alloc_error:
49 return err;
50}
51
52static int st_magn_i2c_remove(struct i2c_client *client)
53{
54 struct iio_dev *indio_dev = i2c_get_clientdata(client);
55 st_magn_common_remove(indio_dev);
56
57 return 0;
58}
59
60static const struct i2c_device_id st_magn_id_table[] = {
61 { LSM303DLHC_MAGN_DEV_NAME },
62 { LSM303DLM_MAGN_DEV_NAME },
63 { LIS3MDL_MAGN_DEV_NAME },
64 {},
65};
66MODULE_DEVICE_TABLE(i2c, st_magn_id_table);
67
68static struct i2c_driver st_magn_driver = {
69 .driver = {
70 .owner = THIS_MODULE,
71 .name = "st-magn-i2c",
72 },
73 .probe = st_magn_i2c_probe,
74 .remove = st_magn_i2c_remove,
75 .id_table = st_magn_id_table,
76};
77module_i2c_driver(st_magn_driver);
78
79MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
80MODULE_DESCRIPTION("STMicroelectronics magnetometers i2c driver");
81MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/magnetometer/st_magn_spi.c b/drivers/iio/magnetometer/st_magn_spi.c
new file mode 100644
index 000000000000..94547e7d6580
--- /dev/null
+++ b/drivers/iio/magnetometer/st_magn_spi.c
@@ -0,0 +1,80 @@
1/*
2 * STMicroelectronics magnetometers driver
3 *
4 * Copyright 2012-2013 STMicroelectronics Inc.
5 *
6 * Denis Ciocca <denis.ciocca@st.com>
7 *
8 * Licensed under the GPL-2.
9 */
10
11#include <linux/kernel.h>
12#include <linux/module.h>
13#include <linux/slab.h>
14#include <linux/spi/spi.h>
15#include <linux/iio/iio.h>
16#include <linux/iio/trigger.h>
17
18#include <linux/iio/common/st_sensors.h>
19#include <linux/iio/common/st_sensors_spi.h>
20#include "st_magn.h"
21
22static int st_magn_spi_probe(struct spi_device *spi)
23{
24 struct iio_dev *indio_dev;
25 struct st_sensor_data *mdata;
26 int err;
27
28 indio_dev = iio_device_alloc(sizeof(*mdata));
29 if (indio_dev == NULL) {
30 err = -ENOMEM;
31 goto iio_device_alloc_error;
32 }
33
34 mdata = iio_priv(indio_dev);
35 mdata->dev = &spi->dev;
36
37 st_sensors_spi_configure(indio_dev, spi, mdata);
38
39 err = st_magn_common_probe(indio_dev);
40 if (err < 0)
41 goto st_magn_common_probe_error;
42
43 return 0;
44
45st_magn_common_probe_error:
46 iio_device_free(indio_dev);
47iio_device_alloc_error:
48 return err;
49}
50
51static int st_magn_spi_remove(struct spi_device *spi)
52{
53 struct iio_dev *indio_dev = spi_get_drvdata(spi);
54 st_magn_common_remove(indio_dev);
55
56 return 0;
57}
58
59static const struct spi_device_id st_magn_id_table[] = {
60 { LSM303DLHC_MAGN_DEV_NAME },
61 { LSM303DLM_MAGN_DEV_NAME },
62 { LIS3MDL_MAGN_DEV_NAME },
63 {},
64};
65MODULE_DEVICE_TABLE(spi, st_magn_id_table);
66
67static struct spi_driver st_magn_driver = {
68 .driver = {
69 .owner = THIS_MODULE,
70 .name = "st-magn-spi",
71 },
72 .probe = st_magn_spi_probe,
73 .remove = st_magn_spi_remove,
74 .id_table = st_magn_id_table,
75};
76module_spi_driver(st_magn_driver);
77
78MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
79MODULE_DESCRIPTION("STMicroelectronics magnetometers spi driver");
80MODULE_LICENSE("GPL v2");