diff options
author | Irina Tirdea <irina.tirdea@intel.com> | 2015-01-11 14:10:15 -0500 |
---|---|---|
committer | Jonathan Cameron <jic23@kernel.org> | 2015-01-27 13:49:56 -0500 |
commit | d5b97f5c7dfcad98927fb4f3b2e99d4c3beeec9a (patch) | |
tree | be9edae8271a45921155e7dee3ea72ba8258eceb /drivers/iio | |
parent | 6da93a6710a3b1eb3d15b88bf96efaac322c893f (diff) |
iio: accel: mma9551: split driver to expose mma955x api
Freescale has the MMA955xL family of devices that use the
same communication protocol (based on i2c messages):
http://www.freescale.com/files/sensors/doc/data_sheet/MMA955xL.pdf.
To support more devices from this family, we need to split the
mma9551 driver so we can export the common functions that will
be used by other mma955x drivers.
Signed-off-by: Irina Tirdea <irina.tirdea@intel.com>
Reviewed-by: Vlad Dogaru <vlad.dogaru@intel.com>
Signed-off-by: Jonathan Cameron <jic23@kernel.org>
Diffstat (limited to 'drivers/iio')
-rw-r--r-- | drivers/iio/accel/Kconfig | 5 | ||||
-rw-r--r-- | drivers/iio/accel/Makefile | 4 | ||||
-rw-r--r-- | drivers/iio/accel/mma9551.c | 443 | ||||
-rw-r--r-- | drivers/iio/accel/mma9551_core.c | 615 | ||||
-rw-r--r-- | drivers/iio/accel/mma9551_core.h | 66 |
5 files changed, 693 insertions, 440 deletions
diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig index 9f67c10291bd..c53047d28ad3 100644 --- a/drivers/iio/accel/Kconfig +++ b/drivers/iio/accel/Kconfig | |||
@@ -111,9 +111,14 @@ config KXCJK1013 | |||
111 | To compile this driver as a module, choose M here: the module will | 111 | To compile this driver as a module, choose M here: the module will |
112 | be called kxcjk-1013. | 112 | be called kxcjk-1013. |
113 | 113 | ||
114 | config MMA9551_CORE | ||
115 | tristate | ||
116 | |||
114 | config MMA9551 | 117 | config MMA9551 |
115 | tristate "Freescale MMA9551L Intelligent Motion-Sensing Platform Driver" | 118 | tristate "Freescale MMA9551L Intelligent Motion-Sensing Platform Driver" |
116 | depends on I2C | 119 | depends on I2C |
120 | select MMA9551_CORE | ||
121 | |||
117 | help | 122 | help |
118 | Say yes here to build support for the Freescale MMA9551L | 123 | Say yes here to build support for the Freescale MMA9551L |
119 | Intelligent Motion-Sensing Platform Driver. | 124 | Intelligent Motion-Sensing Platform Driver. |
diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile index de5b9cb9670f..810531610414 100644 --- a/drivers/iio/accel/Makefile +++ b/drivers/iio/accel/Makefile | |||
@@ -9,7 +9,9 @@ obj-$(CONFIG_HID_SENSOR_ACCEL_3D) += hid-sensor-accel-3d.o | |||
9 | obj-$(CONFIG_KXCJK1013) += kxcjk-1013.o | 9 | obj-$(CONFIG_KXCJK1013) += kxcjk-1013.o |
10 | obj-$(CONFIG_KXSD9) += kxsd9.o | 10 | obj-$(CONFIG_KXSD9) += kxsd9.o |
11 | obj-$(CONFIG_MMA8452) += mma8452.o | 11 | obj-$(CONFIG_MMA8452) += mma8452.o |
12 | obj-$(CONFIG_MMA9551) += mma9551.o | 12 | |
13 | obj-$(CONFIG_MMA9551_CORE) += mma9551_core.o | ||
14 | obj-$(CONFIG_MMA9551) += mma9551.o | ||
13 | 15 | ||
14 | obj-$(CONFIG_IIO_ST_ACCEL_3AXIS) += st_accel.o | 16 | obj-$(CONFIG_IIO_ST_ACCEL_3AXIS) += st_accel.o |
15 | st_accel-y := st_accel_core.o | 17 | st_accel-y := st_accel_core.o |
diff --git a/drivers/iio/accel/mma9551.c b/drivers/iio/accel/mma9551.c index f1a5a06a0726..46c38351c6a3 100644 --- a/drivers/iio/accel/mma9551.c +++ b/drivers/iio/accel/mma9551.c | |||
@@ -23,63 +23,13 @@ | |||
23 | #include <linux/iio/sysfs.h> | 23 | #include <linux/iio/sysfs.h> |
24 | #include <linux/iio/events.h> | 24 | #include <linux/iio/events.h> |
25 | #include <linux/pm_runtime.h> | 25 | #include <linux/pm_runtime.h> |
26 | #include "mma9551_core.h" | ||
26 | 27 | ||
27 | #define MMA9551_DRV_NAME "mma9551" | 28 | #define MMA9551_DRV_NAME "mma9551" |
28 | #define MMA9551_IRQ_NAME "mma9551_event" | 29 | #define MMA9551_IRQ_NAME "mma9551_event" |
29 | #define MMA9551_GPIO_NAME "mma9551_int" | 30 | #define MMA9551_GPIO_NAME "mma9551_int" |
30 | #define MMA9551_GPIO_COUNT 4 | 31 | #define MMA9551_GPIO_COUNT 4 |
31 | 32 | ||
32 | /* Applications IDs */ | ||
33 | #define MMA9551_APPID_VERSION 0x00 | ||
34 | #define MMA9551_APPID_GPIO 0x03 | ||
35 | #define MMA9551_APPID_AFE 0x06 | ||
36 | #define MMA9551_APPID_TILT 0x0B | ||
37 | #define MMA9551_APPID_SLEEP_WAKE 0x12 | ||
38 | #define MMA9551_APPID_RESET 0x17 | ||
39 | #define MMA9551_APPID_NONE 0xff | ||
40 | |||
41 | /* Command masks for mailbox write command */ | ||
42 | #define MMA9551_CMD_READ_VERSION_INFO 0x00 | ||
43 | #define MMA9551_CMD_READ_CONFIG 0x10 | ||
44 | #define MMA9551_CMD_WRITE_CONFIG 0x20 | ||
45 | #define MMA9551_CMD_READ_STATUS 0x30 | ||
46 | |||
47 | enum mma9551_gpio_pin { | ||
48 | mma9551_gpio6 = 0, | ||
49 | mma9551_gpio7, | ||
50 | mma9551_gpio8, | ||
51 | mma9551_gpio9, | ||
52 | mma9551_gpio_max = mma9551_gpio9, | ||
53 | }; | ||
54 | |||
55 | /* Mailbox read command */ | ||
56 | #define MMA9551_RESPONSE_COCO BIT(7) | ||
57 | |||
58 | /* Error-Status codes returned in mailbox read command */ | ||
59 | #define MMA9551_MCI_ERROR_NONE 0x00 | ||
60 | #define MMA9551_MCI_ERROR_PARAM 0x04 | ||
61 | #define MMA9551_MCI_INVALID_COUNT 0x19 | ||
62 | #define MMA9551_MCI_ERROR_COMMAND 0x1C | ||
63 | #define MMA9551_MCI_ERROR_INVALID_LENGTH 0x21 | ||
64 | #define MMA9551_MCI_ERROR_FIFO_BUSY 0x22 | ||
65 | #define MMA9551_MCI_ERROR_FIFO_ALLOCATED 0x23 | ||
66 | #define MMA9551_MCI_ERROR_FIFO_OVERSIZE 0x24 | ||
67 | |||
68 | /* GPIO Application */ | ||
69 | #define MMA9551_GPIO_POL_MSB 0x08 | ||
70 | #define MMA9551_GPIO_POL_LSB 0x09 | ||
71 | |||
72 | /* Sleep/Wake application */ | ||
73 | #define MMA9551_SLEEP_CFG 0x06 | ||
74 | #define MMA9551_SLEEP_CFG_SNCEN BIT(0) | ||
75 | #define MMA9551_SLEEP_CFG_FLEEN BIT(1) | ||
76 | #define MMA9551_SLEEP_CFG_SCHEN BIT(2) | ||
77 | |||
78 | /* AFE application */ | ||
79 | #define MMA9551_AFE_X_ACCEL_REG 0x00 | ||
80 | #define MMA9551_AFE_Y_ACCEL_REG 0x02 | ||
81 | #define MMA9551_AFE_Z_ACCEL_REG 0x04 | ||
82 | |||
83 | /* Tilt application (inclination in IIO terms). */ | 33 | /* Tilt application (inclination in IIO terms). */ |
84 | #define MMA9551_TILT_XZ_ANG_REG 0x00 | 34 | #define MMA9551_TILT_XZ_ANG_REG 0x00 |
85 | #define MMA9551_TILT_YZ_ANG_REG 0x01 | 35 | #define MMA9551_TILT_YZ_ANG_REG 0x01 |
@@ -92,6 +42,8 @@ enum mma9551_gpio_pin { | |||
92 | #define MMA9551_TILT_CFG_REG 0x01 | 42 | #define MMA9551_TILT_CFG_REG 0x01 |
93 | #define MMA9551_TILT_ANG_THRESH_MASK GENMASK(3, 0) | 43 | #define MMA9551_TILT_ANG_THRESH_MASK GENMASK(3, 0) |
94 | 44 | ||
45 | #define MMA9551_DEFAULT_SAMPLE_RATE 122 /* Hz */ | ||
46 | |||
95 | /* Tilt events are mapped to the first three GPIO pins. */ | 47 | /* Tilt events are mapped to the first three GPIO pins. */ |
96 | enum mma9551_tilt_axis { | 48 | enum mma9551_tilt_axis { |
97 | mma9551_x = 0, | 49 | mma9551_x = 0, |
@@ -99,64 +51,6 @@ enum mma9551_tilt_axis { | |||
99 | mma9551_z, | 51 | mma9551_z, |
100 | }; | 52 | }; |
101 | 53 | ||
102 | /* | ||
103 | * A response is composed of: | ||
104 | * - control registers: MB0-3 | ||
105 | * - data registers: MB4-31 | ||
106 | * | ||
107 | * A request is composed of: | ||
108 | * - mbox to write to (always 0) | ||
109 | * - control registers: MB1-4 | ||
110 | * - data registers: MB5-31 | ||
111 | */ | ||
112 | #define MMA9551_MAILBOX_CTRL_REGS 4 | ||
113 | #define MMA9551_MAX_MAILBOX_DATA_REGS 28 | ||
114 | #define MMA9551_MAILBOX_REGS 32 | ||
115 | |||
116 | #define MMA9551_I2C_READ_RETRIES 5 | ||
117 | #define MMA9551_I2C_READ_DELAY 50 /* us */ | ||
118 | |||
119 | #define MMA9551_DEFAULT_SAMPLE_RATE 122 /* Hz */ | ||
120 | #define MMA9551_AUTO_SUSPEND_DELAY_MS 2000 | ||
121 | |||
122 | struct mma9551_mbox_request { | ||
123 | u8 start_mbox; /* Always 0. */ | ||
124 | u8 app_id; | ||
125 | /* | ||
126 | * See Section 5.3.1 of the MMA955xL Software Reference Manual. | ||
127 | * | ||
128 | * Bit 7: reserved, always 0 | ||
129 | * Bits 6-4: command | ||
130 | * Bits 3-0: upper bits of register offset | ||
131 | */ | ||
132 | u8 cmd_off; | ||
133 | u8 lower_off; | ||
134 | u8 nbytes; | ||
135 | u8 buf[MMA9551_MAX_MAILBOX_DATA_REGS - 1]; | ||
136 | } __packed; | ||
137 | |||
138 | struct mma9551_mbox_response { | ||
139 | u8 app_id; | ||
140 | /* | ||
141 | * See Section 5.3.3 of the MMA955xL Software Reference Manual. | ||
142 | * | ||
143 | * Bit 7: COCO | ||
144 | * Bits 6-0: Error code. | ||
145 | */ | ||
146 | u8 coco_err; | ||
147 | u8 nbytes; | ||
148 | u8 req_bytes; | ||
149 | u8 buf[MMA9551_MAX_MAILBOX_DATA_REGS]; | ||
150 | } __packed; | ||
151 | |||
152 | struct mma9551_version_info { | ||
153 | __be32 device_id; | ||
154 | u8 rom_version[2]; | ||
155 | u8 fw_version[2]; | ||
156 | u8 hw_version[2]; | ||
157 | u8 fw_build[2]; | ||
158 | }; | ||
159 | |||
160 | struct mma9551_data { | 54 | struct mma9551_data { |
161 | struct i2c_client *client; | 55 | struct i2c_client *client; |
162 | struct mutex mutex; | 56 | struct mutex mutex; |
@@ -164,285 +58,6 @@ struct mma9551_data { | |||
164 | int irqs[MMA9551_GPIO_COUNT]; | 58 | int irqs[MMA9551_GPIO_COUNT]; |
165 | }; | 59 | }; |
166 | 60 | ||
167 | static int mma9551_transfer(struct i2c_client *client, | ||
168 | u8 app_id, u8 command, u16 offset, | ||
169 | u8 *inbytes, int num_inbytes, | ||
170 | u8 *outbytes, int num_outbytes) | ||
171 | { | ||
172 | struct mma9551_mbox_request req; | ||
173 | struct mma9551_mbox_response rsp; | ||
174 | struct i2c_msg in, out; | ||
175 | u8 req_len, err_code; | ||
176 | int ret, retries; | ||
177 | |||
178 | if (offset >= 1 << 12) { | ||
179 | dev_err(&client->dev, "register offset too large\n"); | ||
180 | return -EINVAL; | ||
181 | } | ||
182 | |||
183 | req_len = 1 + MMA9551_MAILBOX_CTRL_REGS + num_inbytes; | ||
184 | req.start_mbox = 0; | ||
185 | req.app_id = app_id; | ||
186 | req.cmd_off = command | (offset >> 8); | ||
187 | req.lower_off = offset; | ||
188 | |||
189 | if (command == MMA9551_CMD_WRITE_CONFIG) | ||
190 | req.nbytes = num_inbytes; | ||
191 | else | ||
192 | req.nbytes = num_outbytes; | ||
193 | if (num_inbytes) | ||
194 | memcpy(req.buf, inbytes, num_inbytes); | ||
195 | |||
196 | out.addr = client->addr; | ||
197 | out.flags = 0; | ||
198 | out.len = req_len; | ||
199 | out.buf = (u8 *)&req; | ||
200 | |||
201 | ret = i2c_transfer(client->adapter, &out, 1); | ||
202 | if (ret < 0) { | ||
203 | dev_err(&client->dev, "i2c write failed\n"); | ||
204 | return ret; | ||
205 | } | ||
206 | |||
207 | retries = MMA9551_I2C_READ_RETRIES; | ||
208 | do { | ||
209 | udelay(MMA9551_I2C_READ_DELAY); | ||
210 | |||
211 | in.addr = client->addr; | ||
212 | in.flags = I2C_M_RD; | ||
213 | in.len = sizeof(rsp); | ||
214 | in.buf = (u8 *)&rsp; | ||
215 | |||
216 | ret = i2c_transfer(client->adapter, &in, 1); | ||
217 | if (ret < 0) { | ||
218 | dev_err(&client->dev, "i2c read failed\n"); | ||
219 | return ret; | ||
220 | } | ||
221 | |||
222 | if (rsp.coco_err & MMA9551_RESPONSE_COCO) | ||
223 | break; | ||
224 | } while (--retries > 0); | ||
225 | |||
226 | if (retries == 0) { | ||
227 | dev_err(&client->dev, | ||
228 | "timed out while waiting for command response\n"); | ||
229 | return -ETIMEDOUT; | ||
230 | } | ||
231 | |||
232 | if (rsp.app_id != app_id) { | ||
233 | dev_err(&client->dev, | ||
234 | "app_id mismatch in response got %02x expected %02x\n", | ||
235 | rsp.app_id, app_id); | ||
236 | return -EINVAL; | ||
237 | } | ||
238 | |||
239 | err_code = rsp.coco_err & ~MMA9551_RESPONSE_COCO; | ||
240 | if (err_code != MMA9551_MCI_ERROR_NONE) { | ||
241 | dev_err(&client->dev, "read returned error %x\n", err_code); | ||
242 | return -EINVAL; | ||
243 | } | ||
244 | |||
245 | if (rsp.nbytes != rsp.req_bytes) { | ||
246 | dev_err(&client->dev, | ||
247 | "output length mismatch got %d expected %d\n", | ||
248 | rsp.nbytes, rsp.req_bytes); | ||
249 | return -EINVAL; | ||
250 | } | ||
251 | |||
252 | if (num_outbytes) | ||
253 | memcpy(outbytes, rsp.buf, num_outbytes); | ||
254 | |||
255 | return 0; | ||
256 | } | ||
257 | |||
258 | static int mma9551_read_config_byte(struct i2c_client *client, u8 app_id, | ||
259 | u16 reg, u8 *val) | ||
260 | { | ||
261 | return mma9551_transfer(client, app_id, MMA9551_CMD_READ_CONFIG, | ||
262 | reg, NULL, 0, val, 1); | ||
263 | } | ||
264 | |||
265 | static int mma9551_write_config_byte(struct i2c_client *client, u8 app_id, | ||
266 | u16 reg, u8 val) | ||
267 | { | ||
268 | return mma9551_transfer(client, app_id, MMA9551_CMD_WRITE_CONFIG, reg, | ||
269 | &val, 1, NULL, 0); | ||
270 | } | ||
271 | |||
272 | static int mma9551_read_status_byte(struct i2c_client *client, u8 app_id, | ||
273 | u16 reg, u8 *val) | ||
274 | { | ||
275 | return mma9551_transfer(client, app_id, MMA9551_CMD_READ_STATUS, | ||
276 | reg, NULL, 0, val, 1); | ||
277 | } | ||
278 | |||
279 | static int mma9551_read_status_word(struct i2c_client *client, u8 app_id, | ||
280 | u16 reg, u16 *val) | ||
281 | { | ||
282 | int ret; | ||
283 | __be16 v; | ||
284 | |||
285 | ret = mma9551_transfer(client, app_id, MMA9551_CMD_READ_STATUS, | ||
286 | reg, NULL, 0, (u8 *)&v, 2); | ||
287 | *val = be16_to_cpu(v); | ||
288 | |||
289 | return ret; | ||
290 | } | ||
291 | |||
292 | static int mma9551_update_config_bits(struct i2c_client *client, u8 app_id, | ||
293 | u16 reg, u8 mask, u8 val) | ||
294 | { | ||
295 | int ret; | ||
296 | u8 tmp, orig; | ||
297 | |||
298 | ret = mma9551_read_config_byte(client, app_id, reg, &orig); | ||
299 | if (ret < 0) | ||
300 | return ret; | ||
301 | |||
302 | tmp = orig & ~mask; | ||
303 | tmp |= val & mask; | ||
304 | |||
305 | if (tmp == orig) | ||
306 | return 0; | ||
307 | |||
308 | return mma9551_write_config_byte(client, app_id, reg, tmp); | ||
309 | } | ||
310 | |||
311 | /* | ||
312 | * The polarity parameter is described in section 6.2.2, page 66, of the | ||
313 | * Software Reference Manual. Basically, polarity=0 means the interrupt | ||
314 | * line has the same value as the selected bit, while polarity=1 means | ||
315 | * the line is inverted. | ||
316 | */ | ||
317 | static int mma9551_gpio_config(struct i2c_client *client, | ||
318 | enum mma9551_gpio_pin pin, | ||
319 | u8 app_id, u8 bitnum, int polarity) | ||
320 | { | ||
321 | u8 reg, pol_mask, pol_val; | ||
322 | int ret; | ||
323 | |||
324 | if (pin > mma9551_gpio_max) { | ||
325 | dev_err(&client->dev, "bad GPIO pin\n"); | ||
326 | return -EINVAL; | ||
327 | } | ||
328 | |||
329 | /* | ||
330 | * Pin 6 is configured by regs 0x00 and 0x01, pin 7 by 0x02 and | ||
331 | * 0x03, and so on. | ||
332 | */ | ||
333 | reg = pin * 2; | ||
334 | |||
335 | ret = mma9551_write_config_byte(client, MMA9551_APPID_GPIO, | ||
336 | reg, app_id); | ||
337 | if (ret < 0) { | ||
338 | dev_err(&client->dev, "error setting GPIO app_id\n"); | ||
339 | return ret; | ||
340 | } | ||
341 | |||
342 | ret = mma9551_write_config_byte(client, MMA9551_APPID_GPIO, | ||
343 | reg + 1, bitnum); | ||
344 | if (ret < 0) { | ||
345 | dev_err(&client->dev, "error setting GPIO bit number\n"); | ||
346 | return ret; | ||
347 | } | ||
348 | |||
349 | switch (pin) { | ||
350 | case mma9551_gpio6: | ||
351 | reg = MMA9551_GPIO_POL_LSB; | ||
352 | pol_mask = 1 << 6; | ||
353 | break; | ||
354 | case mma9551_gpio7: | ||
355 | reg = MMA9551_GPIO_POL_LSB; | ||
356 | pol_mask = 1 << 7; | ||
357 | break; | ||
358 | case mma9551_gpio8: | ||
359 | reg = MMA9551_GPIO_POL_MSB; | ||
360 | pol_mask = 1 << 0; | ||
361 | break; | ||
362 | case mma9551_gpio9: | ||
363 | reg = MMA9551_GPIO_POL_MSB; | ||
364 | pol_mask = 1 << 1; | ||
365 | break; | ||
366 | } | ||
367 | pol_val = polarity ? pol_mask : 0; | ||
368 | |||
369 | ret = mma9551_update_config_bits(client, MMA9551_APPID_GPIO, reg, | ||
370 | pol_mask, pol_val); | ||
371 | if (ret < 0) | ||
372 | dev_err(&client->dev, "error setting GPIO polarity\n"); | ||
373 | |||
374 | return ret; | ||
375 | } | ||
376 | |||
377 | static int mma9551_read_version(struct i2c_client *client) | ||
378 | { | ||
379 | struct mma9551_version_info info; | ||
380 | int ret; | ||
381 | |||
382 | ret = mma9551_transfer(client, MMA9551_APPID_VERSION, 0x00, 0x00, | ||
383 | NULL, 0, (u8 *)&info, sizeof(info)); | ||
384 | if (ret < 0) | ||
385 | return ret; | ||
386 | |||
387 | dev_info(&client->dev, "Device ID 0x%x, firmware version %02x.%02x\n", | ||
388 | be32_to_cpu(info.device_id), info.fw_version[0], | ||
389 | info.fw_version[1]); | ||
390 | |||
391 | return 0; | ||
392 | } | ||
393 | |||
394 | /* | ||
395 | * Power on chip and enable doze mode. | ||
396 | * Use 'false' as the second parameter to cause the device to enter | ||
397 | * sleep. | ||
398 | */ | ||
399 | static int mma9551_set_device_state(struct i2c_client *client, bool enable) | ||
400 | { | ||
401 | return mma9551_update_config_bits(client, MMA9551_APPID_SLEEP_WAKE, | ||
402 | MMA9551_SLEEP_CFG, | ||
403 | MMA9551_SLEEP_CFG_SNCEN | | ||
404 | MMA9551_SLEEP_CFG_FLEEN | | ||
405 | MMA9551_SLEEP_CFG_SCHEN, | ||
406 | enable ? MMA9551_SLEEP_CFG_SCHEN | | ||
407 | MMA9551_SLEEP_CFG_FLEEN : | ||
408 | MMA9551_SLEEP_CFG_SNCEN); | ||
409 | } | ||
410 | |||
411 | static int mma9551_set_power_state(struct i2c_client *client, bool on) | ||
412 | { | ||
413 | #ifdef CONFIG_PM | ||
414 | int ret; | ||
415 | |||
416 | if (on) | ||
417 | ret = pm_runtime_get_sync(&client->dev); | ||
418 | else { | ||
419 | pm_runtime_mark_last_busy(&client->dev); | ||
420 | ret = pm_runtime_put_autosuspend(&client->dev); | ||
421 | } | ||
422 | |||
423 | if (ret < 0) { | ||
424 | dev_err(&client->dev, | ||
425 | "failed to change power state to %d\n", on); | ||
426 | if (on) | ||
427 | pm_runtime_put_noidle(&client->dev); | ||
428 | |||
429 | return ret; | ||
430 | } | ||
431 | #endif | ||
432 | |||
433 | return 0; | ||
434 | } | ||
435 | |||
436 | static void mma9551_sleep(int freq) | ||
437 | { | ||
438 | int sleep_val = 1000 / freq; | ||
439 | |||
440 | if (sleep_val < 20) | ||
441 | usleep_range(sleep_val * 1000, 20000); | ||
442 | else | ||
443 | msleep_interruptible(sleep_val); | ||
444 | } | ||
445 | |||
446 | static int mma9551_read_incli_chan(struct i2c_client *client, | 61 | static int mma9551_read_incli_chan(struct i2c_client *client, |
447 | const struct iio_chan_spec *chan, | 62 | const struct iio_chan_spec *chan, |
448 | int *val) | 63 | int *val) |
@@ -497,46 +112,6 @@ out_poweroff: | |||
497 | return ret; | 112 | return ret; |
498 | } | 113 | } |
499 | 114 | ||
500 | static int mma9551_read_accel_chan(struct i2c_client *client, | ||
501 | const struct iio_chan_spec *chan, | ||
502 | int *val, int *val2) | ||
503 | { | ||
504 | u16 reg_addr; | ||
505 | s16 raw_accel; | ||
506 | int ret; | ||
507 | |||
508 | switch (chan->channel2) { | ||
509 | case IIO_MOD_X: | ||
510 | reg_addr = MMA9551_AFE_X_ACCEL_REG; | ||
511 | break; | ||
512 | case IIO_MOD_Y: | ||
513 | reg_addr = MMA9551_AFE_Y_ACCEL_REG; | ||
514 | break; | ||
515 | case IIO_MOD_Z: | ||
516 | reg_addr = MMA9551_AFE_Z_ACCEL_REG; | ||
517 | break; | ||
518 | default: | ||
519 | return -EINVAL; | ||
520 | } | ||
521 | |||
522 | ret = mma9551_set_power_state(client, true); | ||
523 | if (ret < 0) | ||
524 | return ret; | ||
525 | |||
526 | ret = mma9551_read_status_word(client, MMA9551_APPID_AFE, | ||
527 | reg_addr, &raw_accel); | ||
528 | if (ret < 0) | ||
529 | goto out_poweroff; | ||
530 | |||
531 | *val = raw_accel; | ||
532 | |||
533 | ret = IIO_VAL_INT; | ||
534 | |||
535 | out_poweroff: | ||
536 | mma9551_set_power_state(client, false); | ||
537 | return ret; | ||
538 | } | ||
539 | |||
540 | static int mma9551_read_raw(struct iio_dev *indio_dev, | 115 | static int mma9551_read_raw(struct iio_dev *indio_dev, |
541 | struct iio_chan_spec const *chan, | 116 | struct iio_chan_spec const *chan, |
542 | int *val, int *val2, long mask) | 117 | int *val, int *val2, long mask) |
@@ -569,9 +144,7 @@ static int mma9551_read_raw(struct iio_dev *indio_dev, | |||
569 | case IIO_CHAN_INFO_SCALE: | 144 | case IIO_CHAN_INFO_SCALE: |
570 | switch (chan->type) { | 145 | switch (chan->type) { |
571 | case IIO_ACCEL: | 146 | case IIO_ACCEL: |
572 | *val = 0; | 147 | return mma9551_read_accel_scale(val, val2); |
573 | *val2 = 2440; | ||
574 | return IIO_VAL_INT_PLUS_MICRO; | ||
575 | default: | 148 | default: |
576 | return -EINVAL; | 149 | return -EINVAL; |
577 | } | 150 | } |
@@ -740,14 +313,6 @@ static const struct iio_event_spec mma9551_incli_event = { | |||
740 | .mask_shared_by_type = BIT(IIO_EV_INFO_VALUE), | 313 | .mask_shared_by_type = BIT(IIO_EV_INFO_VALUE), |
741 | }; | 314 | }; |
742 | 315 | ||
743 | #define MMA9551_ACCEL_CHANNEL(axis) { \ | ||
744 | .type = IIO_ACCEL, \ | ||
745 | .modified = 1, \ | ||
746 | .channel2 = axis, \ | ||
747 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ | ||
748 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ | ||
749 | } | ||
750 | |||
751 | #define MMA9551_INCLI_CHANNEL(axis) { \ | 316 | #define MMA9551_INCLI_CHANNEL(axis) { \ |
752 | .type = IIO_INCLI, \ | 317 | .type = IIO_INCLI, \ |
753 | .modified = 1, \ | 318 | .modified = 1, \ |
diff --git a/drivers/iio/accel/mma9551_core.c b/drivers/iio/accel/mma9551_core.c new file mode 100644 index 000000000000..7f1a73e6aa36 --- /dev/null +++ b/drivers/iio/accel/mma9551_core.c | |||
@@ -0,0 +1,615 @@ | |||
1 | /* | ||
2 | * Common code for Freescale MMA955x Intelligent Sensor Platform drivers | ||
3 | * Copyright (c) 2014, Intel Corporation. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms and conditions of the GNU General Public License, | ||
7 | * version 2, as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | */ | ||
14 | |||
15 | #include <linux/module.h> | ||
16 | #include <linux/i2c.h> | ||
17 | #include <linux/delay.h> | ||
18 | #include <linux/iio/iio.h> | ||
19 | #include <linux/pm_runtime.h> | ||
20 | #include "mma9551_core.h" | ||
21 | |||
22 | /* Command masks for mailbox write command */ | ||
23 | #define MMA9551_CMD_READ_VERSION_INFO 0x00 | ||
24 | #define MMA9551_CMD_READ_CONFIG 0x10 | ||
25 | #define MMA9551_CMD_WRITE_CONFIG 0x20 | ||
26 | #define MMA9551_CMD_READ_STATUS 0x30 | ||
27 | |||
28 | /* Mailbox read command */ | ||
29 | #define MMA9551_RESPONSE_COCO BIT(7) | ||
30 | |||
31 | /* Error-Status codes returned in mailbox read command */ | ||
32 | #define MMA9551_MCI_ERROR_NONE 0x00 | ||
33 | #define MMA9551_MCI_ERROR_PARAM 0x04 | ||
34 | #define MMA9551_MCI_INVALID_COUNT 0x19 | ||
35 | #define MMA9551_MCI_ERROR_COMMAND 0x1C | ||
36 | #define MMA9551_MCI_ERROR_INVALID_LENGTH 0x21 | ||
37 | #define MMA9551_MCI_ERROR_FIFO_BUSY 0x22 | ||
38 | #define MMA9551_MCI_ERROR_FIFO_ALLOCATED 0x23 | ||
39 | #define MMA9551_MCI_ERROR_FIFO_OVERSIZE 0x24 | ||
40 | |||
41 | /* GPIO Application */ | ||
42 | #define MMA9551_GPIO_POL_MSB 0x08 | ||
43 | #define MMA9551_GPIO_POL_LSB 0x09 | ||
44 | |||
45 | /* Sleep/Wake application */ | ||
46 | #define MMA9551_SLEEP_CFG 0x06 | ||
47 | #define MMA9551_SLEEP_CFG_SNCEN BIT(0) | ||
48 | #define MMA9551_SLEEP_CFG_FLEEN BIT(1) | ||
49 | #define MMA9551_SLEEP_CFG_SCHEN BIT(2) | ||
50 | |||
51 | /* AFE application */ | ||
52 | #define MMA9551_AFE_X_ACCEL_REG 0x00 | ||
53 | #define MMA9551_AFE_Y_ACCEL_REG 0x02 | ||
54 | #define MMA9551_AFE_Z_ACCEL_REG 0x04 | ||
55 | |||
56 | /* | ||
57 | * A response is composed of: | ||
58 | * - control registers: MB0-3 | ||
59 | * - data registers: MB4-31 | ||
60 | * | ||
61 | * A request is composed of: | ||
62 | * - mbox to write to (always 0) | ||
63 | * - control registers: MB1-4 | ||
64 | * - data registers: MB5-31 | ||
65 | */ | ||
66 | #define MMA9551_MAILBOX_CTRL_REGS 4 | ||
67 | #define MMA9551_MAX_MAILBOX_DATA_REGS 28 | ||
68 | #define MMA9551_MAILBOX_REGS 32 | ||
69 | |||
70 | #define MMA9551_I2C_READ_RETRIES 5 | ||
71 | #define MMA9551_I2C_READ_DELAY 50 /* us */ | ||
72 | |||
73 | struct mma9551_mbox_request { | ||
74 | u8 start_mbox; /* Always 0. */ | ||
75 | u8 app_id; | ||
76 | /* | ||
77 | * See Section 5.3.1 of the MMA955xL Software Reference Manual. | ||
78 | * | ||
79 | * Bit 7: reserved, always 0 | ||
80 | * Bits 6-4: command | ||
81 | * Bits 3-0: upper bits of register offset | ||
82 | */ | ||
83 | u8 cmd_off; | ||
84 | u8 lower_off; | ||
85 | u8 nbytes; | ||
86 | u8 buf[MMA9551_MAX_MAILBOX_DATA_REGS - 1]; | ||
87 | } __packed; | ||
88 | |||
89 | struct mma9551_mbox_response { | ||
90 | u8 app_id; | ||
91 | /* | ||
92 | * See Section 5.3.3 of the MMA955xL Software Reference Manual. | ||
93 | * | ||
94 | * Bit 7: COCO | ||
95 | * Bits 6-0: Error code. | ||
96 | */ | ||
97 | u8 coco_err; | ||
98 | u8 nbytes; | ||
99 | u8 req_bytes; | ||
100 | u8 buf[MMA9551_MAX_MAILBOX_DATA_REGS]; | ||
101 | } __packed; | ||
102 | |||
103 | struct mma9551_version_info { | ||
104 | __be32 device_id; | ||
105 | u8 rom_version[2]; | ||
106 | u8 fw_version[2]; | ||
107 | u8 hw_version[2]; | ||
108 | u8 fw_build[2]; | ||
109 | }; | ||
110 | |||
111 | static int mma9551_transfer(struct i2c_client *client, | ||
112 | u8 app_id, u8 command, u16 offset, | ||
113 | u8 *inbytes, int num_inbytes, | ||
114 | u8 *outbytes, int num_outbytes) | ||
115 | { | ||
116 | struct mma9551_mbox_request req; | ||
117 | struct mma9551_mbox_response rsp; | ||
118 | struct i2c_msg in, out; | ||
119 | u8 req_len, err_code; | ||
120 | int ret, retries; | ||
121 | |||
122 | if (offset >= 1 << 12) { | ||
123 | dev_err(&client->dev, "register offset too large\n"); | ||
124 | return -EINVAL; | ||
125 | } | ||
126 | |||
127 | req_len = 1 + MMA9551_MAILBOX_CTRL_REGS + num_inbytes; | ||
128 | req.start_mbox = 0; | ||
129 | req.app_id = app_id; | ||
130 | req.cmd_off = command | (offset >> 8); | ||
131 | req.lower_off = offset; | ||
132 | |||
133 | if (command == MMA9551_CMD_WRITE_CONFIG) | ||
134 | req.nbytes = num_inbytes; | ||
135 | else | ||
136 | req.nbytes = num_outbytes; | ||
137 | if (num_inbytes) | ||
138 | memcpy(req.buf, inbytes, num_inbytes); | ||
139 | |||
140 | out.addr = client->addr; | ||
141 | out.flags = 0; | ||
142 | out.len = req_len; | ||
143 | out.buf = (u8 *)&req; | ||
144 | |||
145 | ret = i2c_transfer(client->adapter, &out, 1); | ||
146 | if (ret < 0) { | ||
147 | dev_err(&client->dev, "i2c write failed\n"); | ||
148 | return ret; | ||
149 | } | ||
150 | |||
151 | retries = MMA9551_I2C_READ_RETRIES; | ||
152 | do { | ||
153 | udelay(MMA9551_I2C_READ_DELAY); | ||
154 | |||
155 | in.addr = client->addr; | ||
156 | in.flags = I2C_M_RD; | ||
157 | in.len = sizeof(rsp); | ||
158 | in.buf = (u8 *)&rsp; | ||
159 | |||
160 | ret = i2c_transfer(client->adapter, &in, 1); | ||
161 | if (ret < 0) { | ||
162 | dev_err(&client->dev, "i2c read failed\n"); | ||
163 | return ret; | ||
164 | } | ||
165 | |||
166 | if (rsp.coco_err & MMA9551_RESPONSE_COCO) | ||
167 | break; | ||
168 | } while (--retries > 0); | ||
169 | |||
170 | if (retries == 0) { | ||
171 | dev_err(&client->dev, | ||
172 | "timed out while waiting for command response\n"); | ||
173 | return -ETIMEDOUT; | ||
174 | } | ||
175 | |||
176 | if (rsp.app_id != app_id) { | ||
177 | dev_err(&client->dev, | ||
178 | "app_id mismatch in response got %02x expected %02x\n", | ||
179 | rsp.app_id, app_id); | ||
180 | return -EINVAL; | ||
181 | } | ||
182 | |||
183 | err_code = rsp.coco_err & ~MMA9551_RESPONSE_COCO; | ||
184 | if (err_code != MMA9551_MCI_ERROR_NONE) { | ||
185 | dev_err(&client->dev, "read returned error %x\n", err_code); | ||
186 | return -EINVAL; | ||
187 | } | ||
188 | |||
189 | if (rsp.nbytes != rsp.req_bytes) { | ||
190 | dev_err(&client->dev, | ||
191 | "output length mismatch got %d expected %d\n", | ||
192 | rsp.nbytes, rsp.req_bytes); | ||
193 | return -EINVAL; | ||
194 | } | ||
195 | |||
196 | if (num_outbytes) | ||
197 | memcpy(outbytes, rsp.buf, num_outbytes); | ||
198 | |||
199 | return 0; | ||
200 | } | ||
201 | |||
202 | /** | ||
203 | * mma9551_read_config_byte() - read 1 configuration byte | ||
204 | * @client: I2C client | ||
205 | * @app_id: Application ID | ||
206 | * @reg: Application register | ||
207 | * @val: Pointer to store value read | ||
208 | * | ||
209 | * Read one configuration byte from the device using MMA955xL command format. | ||
210 | * Commands to the MMA955xL platform consist of a write followed | ||
211 | * by one or more reads. | ||
212 | * | ||
213 | * Locking note: This function must be called with the device lock held. | ||
214 | * Locking is not handled inside the function. Callers should ensure they | ||
215 | * serialize access to the HW. | ||
216 | * | ||
217 | * Returns: 0 on success, negative value on failure. | ||
218 | */ | ||
219 | int mma9551_read_config_byte(struct i2c_client *client, u8 app_id, | ||
220 | u16 reg, u8 *val) | ||
221 | { | ||
222 | return mma9551_transfer(client, app_id, MMA9551_CMD_READ_CONFIG, | ||
223 | reg, NULL, 0, val, 1); | ||
224 | } | ||
225 | EXPORT_SYMBOL(mma9551_read_config_byte); | ||
226 | |||
227 | /** | ||
228 | * mma9551_write_config_byte() - write 1 configuration byte | ||
229 | * @client: I2C client | ||
230 | * @app_id: Application ID | ||
231 | * @reg: Application register | ||
232 | * @val: Value to write | ||
233 | * | ||
234 | * Write one configuration byte from the device using MMA955xL command format. | ||
235 | * Commands to the MMA955xL platform consist of a write followed by one or | ||
236 | * more reads. | ||
237 | * | ||
238 | * Locking note: This function must be called with the device lock held. | ||
239 | * Locking is not handled inside the function. Callers should ensure they | ||
240 | * serialize access to the HW. | ||
241 | * | ||
242 | * Returns: 0 on success, negative value on failure. | ||
243 | */ | ||
244 | int mma9551_write_config_byte(struct i2c_client *client, u8 app_id, | ||
245 | u16 reg, u8 val) | ||
246 | { | ||
247 | return mma9551_transfer(client, app_id, MMA9551_CMD_WRITE_CONFIG, reg, | ||
248 | &val, 1, NULL, 0); | ||
249 | } | ||
250 | EXPORT_SYMBOL(mma9551_write_config_byte); | ||
251 | |||
252 | /** | ||
253 | * mma9551_read_status_byte() - read 1 status byte | ||
254 | * @client: I2C client | ||
255 | * @app_id: Application ID | ||
256 | * @reg: Application register | ||
257 | * @val: Pointer to store value read | ||
258 | * | ||
259 | * Read one status byte from the device using MMA955xL command format. | ||
260 | * Commands to the MMA955xL platform consist of a write followed by one or | ||
261 | * more reads. | ||
262 | * | ||
263 | * Locking note: This function must be called with the device lock held. | ||
264 | * Locking is not handled inside the function. Callers should ensure they | ||
265 | * serialize access to the HW. | ||
266 | * | ||
267 | * Returns: 0 on success, negative value on failure. | ||
268 | */ | ||
269 | int mma9551_read_status_byte(struct i2c_client *client, u8 app_id, | ||
270 | u16 reg, u8 *val) | ||
271 | { | ||
272 | return mma9551_transfer(client, app_id, MMA9551_CMD_READ_STATUS, | ||
273 | reg, NULL, 0, val, 1); | ||
274 | } | ||
275 | EXPORT_SYMBOL(mma9551_read_status_byte); | ||
276 | |||
277 | /** | ||
278 | * mma9551_read_status_word() - read 1 status word | ||
279 | * @client: I2C client | ||
280 | * @app_id: Application ID | ||
281 | * @reg: Application register | ||
282 | * @val: Pointer to store value read | ||
283 | * | ||
284 | * Read one status word from the device using MMA955xL command format. | ||
285 | * Commands to the MMA955xL platform consist of a write followed by one or | ||
286 | * more reads. | ||
287 | * | ||
288 | * Locking note: This function must be called with the device lock held. | ||
289 | * Locking is not handled inside the function. Callers should ensure they | ||
290 | * serialize access to the HW. | ||
291 | * | ||
292 | * Returns: 0 on success, negative value on failure. | ||
293 | */ | ||
294 | int mma9551_read_status_word(struct i2c_client *client, u8 app_id, | ||
295 | u16 reg, u16 *val) | ||
296 | { | ||
297 | int ret; | ||
298 | __be16 v; | ||
299 | |||
300 | ret = mma9551_transfer(client, app_id, MMA9551_CMD_READ_STATUS, | ||
301 | reg, NULL, 0, (u8 *)&v, 2); | ||
302 | *val = be16_to_cpu(v); | ||
303 | |||
304 | return ret; | ||
305 | } | ||
306 | EXPORT_SYMBOL(mma9551_read_status_word); | ||
307 | |||
308 | /** | ||
309 | * mma9551_update_config_bits() - update bits in register | ||
310 | * @client: I2C client | ||
311 | * @app_id: Application ID | ||
312 | * @reg: Application register | ||
313 | * @mask: Mask for the bits to update | ||
314 | * @val: Value of the bits to update | ||
315 | * | ||
316 | * Update bits in the given register using a bit mask. | ||
317 | * | ||
318 | * Locking note: This function must be called with the device lock held. | ||
319 | * Locking is not handled inside the function. Callers should ensure they | ||
320 | * serialize access to the HW. | ||
321 | * | ||
322 | * Returns: 0 on success, negative value on failure. | ||
323 | */ | ||
324 | int mma9551_update_config_bits(struct i2c_client *client, u8 app_id, | ||
325 | u16 reg, u8 mask, u8 val) | ||
326 | { | ||
327 | int ret; | ||
328 | u8 tmp, orig; | ||
329 | |||
330 | ret = mma9551_read_config_byte(client, app_id, reg, &orig); | ||
331 | if (ret < 0) | ||
332 | return ret; | ||
333 | |||
334 | tmp = orig & ~mask; | ||
335 | tmp |= val & mask; | ||
336 | |||
337 | if (tmp == orig) | ||
338 | return 0; | ||
339 | |||
340 | return mma9551_write_config_byte(client, app_id, reg, tmp); | ||
341 | } | ||
342 | EXPORT_SYMBOL(mma9551_update_config_bits); | ||
343 | |||
344 | /** | ||
345 | * mma9551_gpio_config() - configure gpio | ||
346 | * @client: I2C client | ||
347 | * @pin: GPIO pin to configure | ||
348 | * @app_id: Application ID | ||
349 | * @bitnum: Bit number of status register being assigned to the GPIO pin. | ||
350 | * @polarity: The polarity parameter is described in section 6.2.2, page 66, | ||
351 | * of the Software Reference Manual. Basically, polarity=0 means | ||
352 | * the interrupt line has the same value as the selected bit, | ||
353 | * while polarity=1 means the line is inverted. | ||
354 | * | ||
355 | * Assign a bit from an application’s status register to a specific GPIO pin. | ||
356 | * | ||
357 | * Locking note: This function must be called with the device lock held. | ||
358 | * Locking is not handled inside the function. Callers should ensure they | ||
359 | * serialize access to the HW. | ||
360 | * | ||
361 | * Returns: 0 on success, negative value on failure. | ||
362 | */ | ||
363 | int mma9551_gpio_config(struct i2c_client *client, enum mma9551_gpio_pin pin, | ||
364 | u8 app_id, u8 bitnum, int polarity) | ||
365 | { | ||
366 | u8 reg, pol_mask, pol_val; | ||
367 | int ret; | ||
368 | |||
369 | if (pin > mma9551_gpio_max) { | ||
370 | dev_err(&client->dev, "bad GPIO pin\n"); | ||
371 | return -EINVAL; | ||
372 | } | ||
373 | |||
374 | /* | ||
375 | * Pin 6 is configured by regs 0x00 and 0x01, pin 7 by 0x02 and | ||
376 | * 0x03, and so on. | ||
377 | */ | ||
378 | reg = pin * 2; | ||
379 | |||
380 | ret = mma9551_write_config_byte(client, MMA9551_APPID_GPIO, | ||
381 | reg, app_id); | ||
382 | if (ret < 0) { | ||
383 | dev_err(&client->dev, "error setting GPIO app_id\n"); | ||
384 | return ret; | ||
385 | } | ||
386 | |||
387 | ret = mma9551_write_config_byte(client, MMA9551_APPID_GPIO, | ||
388 | reg + 1, bitnum); | ||
389 | if (ret < 0) { | ||
390 | dev_err(&client->dev, "error setting GPIO bit number\n"); | ||
391 | return ret; | ||
392 | } | ||
393 | |||
394 | switch (pin) { | ||
395 | case mma9551_gpio6: | ||
396 | reg = MMA9551_GPIO_POL_LSB; | ||
397 | pol_mask = 1 << 6; | ||
398 | break; | ||
399 | case mma9551_gpio7: | ||
400 | reg = MMA9551_GPIO_POL_LSB; | ||
401 | pol_mask = 1 << 7; | ||
402 | break; | ||
403 | case mma9551_gpio8: | ||
404 | reg = MMA9551_GPIO_POL_MSB; | ||
405 | pol_mask = 1 << 0; | ||
406 | break; | ||
407 | case mma9551_gpio9: | ||
408 | reg = MMA9551_GPIO_POL_MSB; | ||
409 | pol_mask = 1 << 1; | ||
410 | break; | ||
411 | } | ||
412 | pol_val = polarity ? pol_mask : 0; | ||
413 | |||
414 | ret = mma9551_update_config_bits(client, MMA9551_APPID_GPIO, reg, | ||
415 | pol_mask, pol_val); | ||
416 | if (ret < 0) | ||
417 | dev_err(&client->dev, "error setting GPIO polarity\n"); | ||
418 | |||
419 | return ret; | ||
420 | } | ||
421 | EXPORT_SYMBOL(mma9551_gpio_config); | ||
422 | |||
423 | /** | ||
424 | * mma9551_read_version() - read device version information | ||
425 | * @client: I2C client | ||
426 | * | ||
427 | * Read version information and print device id and firmware version. | ||
428 | * | ||
429 | * Locking note: This function must be called with the device lock held. | ||
430 | * Locking is not handled inside the function. Callers should ensure they | ||
431 | * serialize access to the HW. | ||
432 | * | ||
433 | * Returns: 0 on success, negative value on failure. | ||
434 | */ | ||
435 | int mma9551_read_version(struct i2c_client *client) | ||
436 | { | ||
437 | struct mma9551_version_info info; | ||
438 | int ret; | ||
439 | |||
440 | ret = mma9551_transfer(client, MMA9551_APPID_VERSION, 0x00, 0x00, | ||
441 | NULL, 0, (u8 *)&info, sizeof(info)); | ||
442 | if (ret < 0) | ||
443 | return ret; | ||
444 | |||
445 | dev_info(&client->dev, "device ID 0x%x, firmware version %02x.%02x\n", | ||
446 | be32_to_cpu(info.device_id), info.fw_version[0], | ||
447 | info.fw_version[1]); | ||
448 | |||
449 | return 0; | ||
450 | } | ||
451 | EXPORT_SYMBOL(mma9551_read_version); | ||
452 | |||
453 | /** | ||
454 | * mma9551_set_device_state() - sets HW power mode | ||
455 | * @client: I2C client | ||
456 | * @enable: Use true to power on device, false to cause the device | ||
457 | * to enter sleep. | ||
458 | * | ||
459 | * Set power on/off for device using the Sleep/Wake Application. | ||
460 | * When enable is true, power on chip and enable doze mode. | ||
461 | * When enable is false, enter sleep mode (device remains in the | ||
462 | * lowest-power mode). | ||
463 | * | ||
464 | * Locking note: This function must be called with the device lock held. | ||
465 | * Locking is not handled inside the function. Callers should ensure they | ||
466 | * serialize access to the HW. | ||
467 | * | ||
468 | * Returns: 0 on success, negative value on failure. | ||
469 | */ | ||
470 | int mma9551_set_device_state(struct i2c_client *client, bool enable) | ||
471 | { | ||
472 | return mma9551_update_config_bits(client, MMA9551_APPID_SLEEP_WAKE, | ||
473 | MMA9551_SLEEP_CFG, | ||
474 | MMA9551_SLEEP_CFG_SNCEN | | ||
475 | MMA9551_SLEEP_CFG_FLEEN | | ||
476 | MMA9551_SLEEP_CFG_SCHEN, | ||
477 | enable ? MMA9551_SLEEP_CFG_SCHEN | | ||
478 | MMA9551_SLEEP_CFG_FLEEN : | ||
479 | MMA9551_SLEEP_CFG_SNCEN); | ||
480 | } | ||
481 | EXPORT_SYMBOL(mma9551_set_device_state); | ||
482 | |||
483 | /** | ||
484 | * mma9551_set_power_state() - sets runtime PM state | ||
485 | * @client: I2C client | ||
486 | * @on: Use true to power on device, false to power off | ||
487 | * | ||
488 | * Resume or suspend the device using Runtime PM. | ||
489 | * The device will suspend after the autosuspend delay. | ||
490 | * | ||
491 | * Returns: 0 on success, negative value on failure. | ||
492 | */ | ||
493 | int mma9551_set_power_state(struct i2c_client *client, bool on) | ||
494 | { | ||
495 | #ifdef CONFIG_PM | ||
496 | int ret; | ||
497 | |||
498 | if (on) | ||
499 | ret = pm_runtime_get_sync(&client->dev); | ||
500 | else { | ||
501 | pm_runtime_mark_last_busy(&client->dev); | ||
502 | ret = pm_runtime_put_autosuspend(&client->dev); | ||
503 | } | ||
504 | |||
505 | if (ret < 0) { | ||
506 | dev_err(&client->dev, | ||
507 | "failed to change power state to %d\n", on); | ||
508 | if (on) | ||
509 | pm_runtime_put_noidle(&client->dev); | ||
510 | |||
511 | return ret; | ||
512 | } | ||
513 | #endif | ||
514 | |||
515 | return 0; | ||
516 | } | ||
517 | EXPORT_SYMBOL(mma9551_set_power_state); | ||
518 | |||
519 | /** | ||
520 | * mma9551_sleep() - sleep | ||
521 | * @freq: Application frequency | ||
522 | * | ||
523 | * Firmware applications run at a certain frequency on the | ||
524 | * device. Sleep for one application cycle to make sure the | ||
525 | * application had time to run once and initialize set values. | ||
526 | */ | ||
527 | void mma9551_sleep(int freq) | ||
528 | { | ||
529 | int sleep_val = 1000 / freq; | ||
530 | |||
531 | if (sleep_val < 20) | ||
532 | usleep_range(sleep_val * 1000, 20000); | ||
533 | else | ||
534 | msleep_interruptible(sleep_val); | ||
535 | } | ||
536 | EXPORT_SYMBOL(mma9551_sleep); | ||
537 | |||
538 | /** | ||
539 | * mma9551_read_accel_chan() - read accelerometer channel | ||
540 | * @client: I2C client | ||
541 | * @chan: IIO channel | ||
542 | * @val: Pointer to the accelerometer value read | ||
543 | * @val2: Unused | ||
544 | * | ||
545 | * Read accelerometer value for the specified channel. | ||
546 | * | ||
547 | * Locking note: This function must be called with the device lock held. | ||
548 | * Locking is not handled inside the function. Callers should ensure they | ||
549 | * serialize access to the HW. | ||
550 | * | ||
551 | * Returns: IIO_VAL_INT on success, negative value on failure. | ||
552 | */ | ||
553 | int mma9551_read_accel_chan(struct i2c_client *client, | ||
554 | const struct iio_chan_spec *chan, | ||
555 | int *val, int *val2) | ||
556 | { | ||
557 | u16 reg_addr; | ||
558 | s16 raw_accel; | ||
559 | int ret; | ||
560 | |||
561 | switch (chan->channel2) { | ||
562 | case IIO_MOD_X: | ||
563 | reg_addr = MMA9551_AFE_X_ACCEL_REG; | ||
564 | break; | ||
565 | case IIO_MOD_Y: | ||
566 | reg_addr = MMA9551_AFE_Y_ACCEL_REG; | ||
567 | break; | ||
568 | case IIO_MOD_Z: | ||
569 | reg_addr = MMA9551_AFE_Z_ACCEL_REG; | ||
570 | break; | ||
571 | default: | ||
572 | return -EINVAL; | ||
573 | } | ||
574 | |||
575 | ret = mma9551_set_power_state(client, true); | ||
576 | if (ret < 0) | ||
577 | return ret; | ||
578 | |||
579 | ret = mma9551_read_status_word(client, MMA9551_APPID_AFE, | ||
580 | reg_addr, &raw_accel); | ||
581 | if (ret < 0) | ||
582 | goto out_poweroff; | ||
583 | |||
584 | *val = raw_accel; | ||
585 | |||
586 | ret = IIO_VAL_INT; | ||
587 | |||
588 | out_poweroff: | ||
589 | mma9551_set_power_state(client, false); | ||
590 | return ret; | ||
591 | } | ||
592 | EXPORT_SYMBOL(mma9551_read_accel_chan); | ||
593 | |||
594 | /** | ||
595 | * mma9551_read_accel_scale() - read accelerometer scale | ||
596 | * @val: Pointer to the accelerometer scale (int value) | ||
597 | * @val2: Pointer to the accelerometer scale (micro value) | ||
598 | * | ||
599 | * Read accelerometer scale. | ||
600 | * | ||
601 | * Returns: IIO_VAL_INT_PLUS_MICRO. | ||
602 | */ | ||
603 | int mma9551_read_accel_scale(int *val, int *val2) | ||
604 | { | ||
605 | *val = 0; | ||
606 | *val2 = 2440; | ||
607 | |||
608 | return IIO_VAL_INT_PLUS_MICRO; | ||
609 | } | ||
610 | EXPORT_SYMBOL(mma9551_read_accel_scale); | ||
611 | |||
612 | MODULE_AUTHOR("Irina Tirdea <irina.tirdea@intel.com>"); | ||
613 | MODULE_AUTHOR("Vlad Dogaru <vlad.dogaru@intel.com>"); | ||
614 | MODULE_LICENSE("GPL v2"); | ||
615 | MODULE_DESCRIPTION("MMA955xL sensors core"); | ||
diff --git a/drivers/iio/accel/mma9551_core.h b/drivers/iio/accel/mma9551_core.h new file mode 100644 index 000000000000..e6efd027f49a --- /dev/null +++ b/drivers/iio/accel/mma9551_core.h | |||
@@ -0,0 +1,66 @@ | |||
1 | /* | ||
2 | * Common code for Freescale MMA955x Intelligent Sensor Platform drivers | ||
3 | * Copyright (c) 2014, Intel Corporation. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms and conditions of the GNU General Public License, | ||
7 | * version 2, as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | */ | ||
14 | |||
15 | #ifndef _MMA9551_CORE_H_ | ||
16 | #define _MMA9551_CORE_H_ | ||
17 | |||
18 | /* Applications IDs */ | ||
19 | #define MMA9551_APPID_VERSION 0x00 | ||
20 | #define MMA9551_APPID_GPIO 0x03 | ||
21 | #define MMA9551_APPID_AFE 0x06 | ||
22 | #define MMA9551_APPID_TILT 0x0B | ||
23 | #define MMA9551_APPID_SLEEP_WAKE 0x12 | ||
24 | #define MMA9551_APPID_RESET 0x17 | ||
25 | #define MMA9551_APPID_NONE 0xff | ||
26 | |||
27 | #define MMA9551_AUTO_SUSPEND_DELAY_MS 2000 | ||
28 | |||
29 | enum mma9551_gpio_pin { | ||
30 | mma9551_gpio6 = 0, | ||
31 | mma9551_gpio7, | ||
32 | mma9551_gpio8, | ||
33 | mma9551_gpio9, | ||
34 | mma9551_gpio_max = mma9551_gpio9, | ||
35 | }; | ||
36 | |||
37 | #define MMA9551_ACCEL_CHANNEL(axis) { \ | ||
38 | .type = IIO_ACCEL, \ | ||
39 | .modified = 1, \ | ||
40 | .channel2 = axis, \ | ||
41 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ | ||
42 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ | ||
43 | } | ||
44 | |||
45 | int mma9551_read_config_byte(struct i2c_client *client, u8 app_id, | ||
46 | u16 reg, u8 *val); | ||
47 | int mma9551_write_config_byte(struct i2c_client *client, u8 app_id, | ||
48 | u16 reg, u8 val); | ||
49 | int mma9551_read_status_byte(struct i2c_client *client, u8 app_id, | ||
50 | u16 reg, u8 *val); | ||
51 | int mma9551_read_status_word(struct i2c_client *client, u8 app_id, | ||
52 | u16 reg, u16 *val); | ||
53 | int mma9551_update_config_bits(struct i2c_client *client, u8 app_id, | ||
54 | u16 reg, u8 mask, u8 val); | ||
55 | int mma9551_gpio_config(struct i2c_client *client, enum mma9551_gpio_pin pin, | ||
56 | u8 app_id, u8 bitnum, int polarity); | ||
57 | int mma9551_read_version(struct i2c_client *client); | ||
58 | int mma9551_set_device_state(struct i2c_client *client, bool enable); | ||
59 | int mma9551_set_power_state(struct i2c_client *client, bool on); | ||
60 | void mma9551_sleep(int freq); | ||
61 | int mma9551_read_accel_chan(struct i2c_client *client, | ||
62 | const struct iio_chan_spec *chan, | ||
63 | int *val, int *val2); | ||
64 | int mma9551_read_accel_scale(int *val, int *val2); | ||
65 | |||
66 | #endif /* _MMA9551_CORE_H_ */ | ||