Commit | Line | Data |
---|---|---|
2025cf9e | 1 | // SPDX-License-Identifier: GPL-2.0-only |
d5b97f5c IT |
2 | /* |
3 | * Common code for Freescale MMA955x Intelligent Sensor Platform drivers | |
4 | * Copyright (c) 2014, Intel Corporation. | |
d5b97f5c IT |
5 | */ |
6 | ||
7 | #include <linux/module.h> | |
8 | #include <linux/i2c.h> | |
9 | #include <linux/delay.h> | |
10 | #include <linux/iio/iio.h> | |
11 | #include <linux/pm_runtime.h> | |
12 | #include "mma9551_core.h" | |
13 | ||
14 | /* Command masks for mailbox write command */ | |
15 | #define MMA9551_CMD_READ_VERSION_INFO 0x00 | |
16 | #define MMA9551_CMD_READ_CONFIG 0x10 | |
17 | #define MMA9551_CMD_WRITE_CONFIG 0x20 | |
18 | #define MMA9551_CMD_READ_STATUS 0x30 | |
19 | ||
20 | /* Mailbox read command */ | |
21 | #define MMA9551_RESPONSE_COCO BIT(7) | |
22 | ||
23 | /* Error-Status codes returned in mailbox read command */ | |
24 | #define MMA9551_MCI_ERROR_NONE 0x00 | |
25 | #define MMA9551_MCI_ERROR_PARAM 0x04 | |
26 | #define MMA9551_MCI_INVALID_COUNT 0x19 | |
27 | #define MMA9551_MCI_ERROR_COMMAND 0x1C | |
28 | #define MMA9551_MCI_ERROR_INVALID_LENGTH 0x21 | |
29 | #define MMA9551_MCI_ERROR_FIFO_BUSY 0x22 | |
30 | #define MMA9551_MCI_ERROR_FIFO_ALLOCATED 0x23 | |
31 | #define MMA9551_MCI_ERROR_FIFO_OVERSIZE 0x24 | |
32 | ||
33 | /* GPIO Application */ | |
34 | #define MMA9551_GPIO_POL_MSB 0x08 | |
35 | #define MMA9551_GPIO_POL_LSB 0x09 | |
36 | ||
37 | /* Sleep/Wake application */ | |
38 | #define MMA9551_SLEEP_CFG 0x06 | |
39 | #define MMA9551_SLEEP_CFG_SNCEN BIT(0) | |
40 | #define MMA9551_SLEEP_CFG_FLEEN BIT(1) | |
41 | #define MMA9551_SLEEP_CFG_SCHEN BIT(2) | |
42 | ||
43 | /* AFE application */ | |
44 | #define MMA9551_AFE_X_ACCEL_REG 0x00 | |
45 | #define MMA9551_AFE_Y_ACCEL_REG 0x02 | |
46 | #define MMA9551_AFE_Z_ACCEL_REG 0x04 | |
47 | ||
40cb7613 IT |
48 | /* Reset/Suspend/Clear application */ |
49 | #define MMA9551_RSC_RESET 0x00 | |
50 | #define MMA9551_RSC_OFFSET(mask) (3 - (ffs(mask) - 1) / 8) | |
51 | #define MMA9551_RSC_VAL(mask) (mask >> (((ffs(mask) - 1) / 8) * 8)) | |
52 | ||
d5b97f5c IT |
53 | /* |
54 | * A response is composed of: | |
55 | * - control registers: MB0-3 | |
56 | * - data registers: MB4-31 | |
57 | * | |
58 | * A request is composed of: | |
59 | * - mbox to write to (always 0) | |
60 | * - control registers: MB1-4 | |
61 | * - data registers: MB5-31 | |
62 | */ | |
63 | #define MMA9551_MAILBOX_CTRL_REGS 4 | |
64 | #define MMA9551_MAX_MAILBOX_DATA_REGS 28 | |
65 | #define MMA9551_MAILBOX_REGS 32 | |
66 | ||
67 | #define MMA9551_I2C_READ_RETRIES 5 | |
68 | #define MMA9551_I2C_READ_DELAY 50 /* us */ | |
69 | ||
70 | struct mma9551_mbox_request { | |
71 | u8 start_mbox; /* Always 0. */ | |
72 | u8 app_id; | |
73 | /* | |
74 | * See Section 5.3.1 of the MMA955xL Software Reference Manual. | |
75 | * | |
76 | * Bit 7: reserved, always 0 | |
77 | * Bits 6-4: command | |
78 | * Bits 3-0: upper bits of register offset | |
79 | */ | |
80 | u8 cmd_off; | |
81 | u8 lower_off; | |
82 | u8 nbytes; | |
83 | u8 buf[MMA9551_MAX_MAILBOX_DATA_REGS - 1]; | |
84 | } __packed; | |
85 | ||
86 | struct mma9551_mbox_response { | |
87 | u8 app_id; | |
88 | /* | |
89 | * See Section 5.3.3 of the MMA955xL Software Reference Manual. | |
90 | * | |
91 | * Bit 7: COCO | |
92 | * Bits 6-0: Error code. | |
93 | */ | |
94 | u8 coco_err; | |
95 | u8 nbytes; | |
96 | u8 req_bytes; | |
97 | u8 buf[MMA9551_MAX_MAILBOX_DATA_REGS]; | |
98 | } __packed; | |
99 | ||
100 | struct mma9551_version_info { | |
101 | __be32 device_id; | |
102 | u8 rom_version[2]; | |
103 | u8 fw_version[2]; | |
104 | u8 hw_version[2]; | |
105 | u8 fw_build[2]; | |
106 | }; | |
107 | ||
108 | static int mma9551_transfer(struct i2c_client *client, | |
109 | u8 app_id, u8 command, u16 offset, | |
110 | u8 *inbytes, int num_inbytes, | |
111 | u8 *outbytes, int num_outbytes) | |
112 | { | |
113 | struct mma9551_mbox_request req; | |
114 | struct mma9551_mbox_response rsp; | |
115 | struct i2c_msg in, out; | |
116 | u8 req_len, err_code; | |
117 | int ret, retries; | |
118 | ||
119 | if (offset >= 1 << 12) { | |
120 | dev_err(&client->dev, "register offset too large\n"); | |
121 | return -EINVAL; | |
122 | } | |
123 | ||
124 | req_len = 1 + MMA9551_MAILBOX_CTRL_REGS + num_inbytes; | |
125 | req.start_mbox = 0; | |
126 | req.app_id = app_id; | |
127 | req.cmd_off = command | (offset >> 8); | |
128 | req.lower_off = offset; | |
129 | ||
130 | if (command == MMA9551_CMD_WRITE_CONFIG) | |
131 | req.nbytes = num_inbytes; | |
132 | else | |
133 | req.nbytes = num_outbytes; | |
134 | if (num_inbytes) | |
135 | memcpy(req.buf, inbytes, num_inbytes); | |
136 | ||
137 | out.addr = client->addr; | |
138 | out.flags = 0; | |
139 | out.len = req_len; | |
140 | out.buf = (u8 *)&req; | |
141 | ||
142 | ret = i2c_transfer(client->adapter, &out, 1); | |
143 | if (ret < 0) { | |
144 | dev_err(&client->dev, "i2c write failed\n"); | |
145 | return ret; | |
146 | } | |
147 | ||
148 | retries = MMA9551_I2C_READ_RETRIES; | |
149 | do { | |
150 | udelay(MMA9551_I2C_READ_DELAY); | |
151 | ||
152 | in.addr = client->addr; | |
153 | in.flags = I2C_M_RD; | |
154 | in.len = sizeof(rsp); | |
155 | in.buf = (u8 *)&rsp; | |
156 | ||
157 | ret = i2c_transfer(client->adapter, &in, 1); | |
158 | if (ret < 0) { | |
159 | dev_err(&client->dev, "i2c read failed\n"); | |
160 | return ret; | |
161 | } | |
162 | ||
163 | if (rsp.coco_err & MMA9551_RESPONSE_COCO) | |
164 | break; | |
165 | } while (--retries > 0); | |
166 | ||
167 | if (retries == 0) { | |
168 | dev_err(&client->dev, | |
169 | "timed out while waiting for command response\n"); | |
170 | return -ETIMEDOUT; | |
171 | } | |
172 | ||
173 | if (rsp.app_id != app_id) { | |
174 | dev_err(&client->dev, | |
175 | "app_id mismatch in response got %02x expected %02x\n", | |
176 | rsp.app_id, app_id); | |
177 | return -EINVAL; | |
178 | } | |
179 | ||
180 | err_code = rsp.coco_err & ~MMA9551_RESPONSE_COCO; | |
181 | if (err_code != MMA9551_MCI_ERROR_NONE) { | |
182 | dev_err(&client->dev, "read returned error %x\n", err_code); | |
183 | return -EINVAL; | |
184 | } | |
185 | ||
186 | if (rsp.nbytes != rsp.req_bytes) { | |
187 | dev_err(&client->dev, | |
188 | "output length mismatch got %d expected %d\n", | |
189 | rsp.nbytes, rsp.req_bytes); | |
190 | return -EINVAL; | |
191 | } | |
192 | ||
193 | if (num_outbytes) | |
194 | memcpy(outbytes, rsp.buf, num_outbytes); | |
195 | ||
196 | return 0; | |
197 | } | |
198 | ||
199 | /** | |
200 | * mma9551_read_config_byte() - read 1 configuration byte | |
201 | * @client: I2C client | |
202 | * @app_id: Application ID | |
203 | * @reg: Application register | |
204 | * @val: Pointer to store value read | |
205 | * | |
206 | * Read one configuration byte from the device using MMA955xL command format. | |
207 | * Commands to the MMA955xL platform consist of a write followed | |
208 | * by one or more reads. | |
209 | * | |
210 | * Locking note: This function must be called with the device lock held. | |
211 | * Locking is not handled inside the function. Callers should ensure they | |
212 | * serialize access to the HW. | |
213 | * | |
214 | * Returns: 0 on success, negative value on failure. | |
215 | */ | |
216 | int mma9551_read_config_byte(struct i2c_client *client, u8 app_id, | |
217 | u16 reg, u8 *val) | |
218 | { | |
219 | return mma9551_transfer(client, app_id, MMA9551_CMD_READ_CONFIG, | |
220 | reg, NULL, 0, val, 1); | |
221 | } | |
222 | EXPORT_SYMBOL(mma9551_read_config_byte); | |
223 | ||
224 | /** | |
225 | * mma9551_write_config_byte() - write 1 configuration byte | |
226 | * @client: I2C client | |
227 | * @app_id: Application ID | |
228 | * @reg: Application register | |
229 | * @val: Value to write | |
230 | * | |
231 | * Write one configuration byte from the device using MMA955xL command format. | |
232 | * Commands to the MMA955xL platform consist of a write followed by one or | |
233 | * more reads. | |
234 | * | |
235 | * Locking note: This function must be called with the device lock held. | |
236 | * Locking is not handled inside the function. Callers should ensure they | |
237 | * serialize access to the HW. | |
238 | * | |
239 | * Returns: 0 on success, negative value on failure. | |
240 | */ | |
241 | int mma9551_write_config_byte(struct i2c_client *client, u8 app_id, | |
242 | u16 reg, u8 val) | |
243 | { | |
244 | return mma9551_transfer(client, app_id, MMA9551_CMD_WRITE_CONFIG, reg, | |
245 | &val, 1, NULL, 0); | |
246 | } | |
247 | EXPORT_SYMBOL(mma9551_write_config_byte); | |
248 | ||
249 | /** | |
250 | * mma9551_read_status_byte() - read 1 status byte | |
251 | * @client: I2C client | |
252 | * @app_id: Application ID | |
253 | * @reg: Application register | |
254 | * @val: Pointer to store value read | |
255 | * | |
256 | * Read one status byte from the device using MMA955xL command format. | |
257 | * Commands to the MMA955xL platform consist of a write followed by one or | |
258 | * more reads. | |
259 | * | |
260 | * Locking note: This function must be called with the device lock held. | |
261 | * Locking is not handled inside the function. Callers should ensure they | |
262 | * serialize access to the HW. | |
263 | * | |
264 | * Returns: 0 on success, negative value on failure. | |
265 | */ | |
266 | int mma9551_read_status_byte(struct i2c_client *client, u8 app_id, | |
267 | u16 reg, u8 *val) | |
268 | { | |
269 | return mma9551_transfer(client, app_id, MMA9551_CMD_READ_STATUS, | |
270 | reg, NULL, 0, val, 1); | |
271 | } | |
272 | EXPORT_SYMBOL(mma9551_read_status_byte); | |
273 | ||
40cb7613 IT |
274 | /** |
275 | * mma9551_read_config_word() - read 1 config word | |
276 | * @client: I2C client | |
277 | * @app_id: Application ID | |
278 | * @reg: Application register | |
279 | * @val: Pointer to store value read | |
280 | * | |
281 | * Read one configuration word from the device using MMA955xL command format. | |
282 | * Commands to the MMA955xL platform consist of a write followed by one or | |
283 | * more reads. | |
284 | * | |
285 | * Locking note: This function must be called with the device lock held. | |
286 | * Locking is not handled inside the function. Callers should ensure they | |
287 | * serialize access to the HW. | |
288 | * | |
289 | * Returns: 0 on success, negative value on failure. | |
290 | */ | |
291 | int mma9551_read_config_word(struct i2c_client *client, u8 app_id, | |
b37c1990 | 292 | u16 reg, u16 *val) |
40cb7613 IT |
293 | { |
294 | int ret; | |
295 | __be16 v; | |
296 | ||
297 | ret = mma9551_transfer(client, app_id, MMA9551_CMD_READ_CONFIG, | |
298 | reg, NULL, 0, (u8 *)&v, 2); | |
299 | *val = be16_to_cpu(v); | |
300 | ||
301 | return ret; | |
302 | } | |
303 | EXPORT_SYMBOL(mma9551_read_config_word); | |
304 | ||
305 | /** | |
306 | * mma9551_write_config_word() - write 1 config word | |
307 | * @client: I2C client | |
308 | * @app_id: Application ID | |
309 | * @reg: Application register | |
310 | * @val: Value to write | |
311 | * | |
312 | * Write one configuration word from the device using MMA955xL command format. | |
313 | * Commands to the MMA955xL platform consist of a write followed by one or | |
314 | * more reads. | |
315 | * | |
316 | * Locking note: This function must be called with the device lock held. | |
317 | * Locking is not handled inside the function. Callers should ensure they | |
318 | * serialize access to the HW. | |
319 | * | |
320 | * Returns: 0 on success, negative value on failure. | |
321 | */ | |
322 | int mma9551_write_config_word(struct i2c_client *client, u8 app_id, | |
b37c1990 | 323 | u16 reg, u16 val) |
40cb7613 IT |
324 | { |
325 | __be16 v = cpu_to_be16(val); | |
326 | ||
327 | return mma9551_transfer(client, app_id, MMA9551_CMD_WRITE_CONFIG, reg, | |
b37c1990 | 328 | (u8 *)&v, 2, NULL, 0); |
40cb7613 IT |
329 | } |
330 | EXPORT_SYMBOL(mma9551_write_config_word); | |
331 | ||
d5b97f5c IT |
332 | /** |
333 | * mma9551_read_status_word() - read 1 status word | |
334 | * @client: I2C client | |
335 | * @app_id: Application ID | |
336 | * @reg: Application register | |
337 | * @val: Pointer to store value read | |
338 | * | |
339 | * Read one status word from the device using MMA955xL command format. | |
340 | * Commands to the MMA955xL platform consist of a write followed by one or | |
341 | * more reads. | |
342 | * | |
343 | * Locking note: This function must be called with the device lock held. | |
344 | * Locking is not handled inside the function. Callers should ensure they | |
345 | * serialize access to the HW. | |
346 | * | |
347 | * Returns: 0 on success, negative value on failure. | |
348 | */ | |
349 | int mma9551_read_status_word(struct i2c_client *client, u8 app_id, | |
350 | u16 reg, u16 *val) | |
351 | { | |
352 | int ret; | |
353 | __be16 v; | |
354 | ||
355 | ret = mma9551_transfer(client, app_id, MMA9551_CMD_READ_STATUS, | |
356 | reg, NULL, 0, (u8 *)&v, 2); | |
357 | *val = be16_to_cpu(v); | |
358 | ||
359 | return ret; | |
360 | } | |
361 | EXPORT_SYMBOL(mma9551_read_status_word); | |
362 | ||
40cb7613 IT |
363 | /** |
364 | * mma9551_read_config_words() - read multiple config words | |
365 | * @client: I2C client | |
366 | * @app_id: Application ID | |
367 | * @reg: Application register | |
c0d901cc | 368 | * @len: Length of array to read (in words) |
b39f0c94 | 369 | * @buf: Array of words to read |
40cb7613 IT |
370 | * |
371 | * Read multiple configuration registers (word-sized registers). | |
372 | * | |
373 | * Locking note: This function must be called with the device lock held. | |
374 | * Locking is not handled inside the function. Callers should ensure they | |
375 | * serialize access to the HW. | |
376 | * | |
377 | * Returns: 0 on success, negative value on failure. | |
378 | */ | |
379 | int mma9551_read_config_words(struct i2c_client *client, u8 app_id, | |
b37c1990 | 380 | u16 reg, u8 len, u16 *buf) |
40cb7613 IT |
381 | { |
382 | int ret, i; | |
2a4d2032 IT |
383 | __be16 be_buf[MMA9551_MAX_MAILBOX_DATA_REGS / 2]; |
384 | ||
c0d901cc | 385 | if (len > ARRAY_SIZE(be_buf)) { |
2a4d2032 IT |
386 | dev_err(&client->dev, "Invalid buffer size %d\n", len); |
387 | return -EINVAL; | |
388 | } | |
40cb7613 IT |
389 | |
390 | ret = mma9551_transfer(client, app_id, MMA9551_CMD_READ_CONFIG, | |
c0d901cc | 391 | reg, NULL, 0, (u8 *)be_buf, len * sizeof(u16)); |
40cb7613 IT |
392 | if (ret < 0) |
393 | return ret; | |
394 | ||
c0d901cc | 395 | for (i = 0; i < len; i++) |
40cb7613 IT |
396 | buf[i] = be16_to_cpu(be_buf[i]); |
397 | ||
398 | return 0; | |
399 | } | |
400 | EXPORT_SYMBOL(mma9551_read_config_words); | |
401 | ||
402 | /** | |
403 | * mma9551_read_status_words() - read multiple status words | |
404 | * @client: I2C client | |
405 | * @app_id: Application ID | |
406 | * @reg: Application register | |
c0d901cc | 407 | * @len: Length of array to read (in words) |
b39f0c94 | 408 | * @buf: Array of words to read |
40cb7613 IT |
409 | * |
410 | * Read multiple status registers (word-sized registers). | |
411 | * | |
412 | * Locking note: This function must be called with the device lock held. | |
413 | * Locking is not handled inside the function. Callers should ensure they | |
414 | * serialize access to the HW. | |
415 | * | |
416 | * Returns: 0 on success, negative value on failure. | |
417 | */ | |
418 | int mma9551_read_status_words(struct i2c_client *client, u8 app_id, | |
419 | u16 reg, u8 len, u16 *buf) | |
420 | { | |
421 | int ret, i; | |
2a4d2032 IT |
422 | __be16 be_buf[MMA9551_MAX_MAILBOX_DATA_REGS / 2]; |
423 | ||
c0d901cc | 424 | if (len > ARRAY_SIZE(be_buf)) { |
2a4d2032 IT |
425 | dev_err(&client->dev, "Invalid buffer size %d\n", len); |
426 | return -EINVAL; | |
427 | } | |
40cb7613 IT |
428 | |
429 | ret = mma9551_transfer(client, app_id, MMA9551_CMD_READ_STATUS, | |
c0d901cc | 430 | reg, NULL, 0, (u8 *)be_buf, len * sizeof(u16)); |
40cb7613 IT |
431 | if (ret < 0) |
432 | return ret; | |
433 | ||
c0d901cc | 434 | for (i = 0; i < len; i++) |
40cb7613 IT |
435 | buf[i] = be16_to_cpu(be_buf[i]); |
436 | ||
437 | return 0; | |
438 | } | |
439 | EXPORT_SYMBOL(mma9551_read_status_words); | |
440 | ||
441 | /** | |
442 | * mma9551_write_config_words() - write multiple config words | |
443 | * @client: I2C client | |
444 | * @app_id: Application ID | |
445 | * @reg: Application register | |
c0d901cc | 446 | * @len: Length of array to write (in words) |
b39f0c94 | 447 | * @buf: Array of words to write |
40cb7613 IT |
448 | * |
449 | * Write multiple configuration registers (word-sized registers). | |
450 | * | |
451 | * Locking note: This function must be called with the device lock held. | |
452 | * Locking is not handled inside the function. Callers should ensure they | |
453 | * serialize access to the HW. | |
454 | * | |
455 | * Returns: 0 on success, negative value on failure. | |
456 | */ | |
457 | int mma9551_write_config_words(struct i2c_client *client, u8 app_id, | |
458 | u16 reg, u8 len, u16 *buf) | |
459 | { | |
460 | int i; | |
2a4d2032 IT |
461 | __be16 be_buf[(MMA9551_MAX_MAILBOX_DATA_REGS - 1) / 2]; |
462 | ||
c0d901cc | 463 | if (len > ARRAY_SIZE(be_buf)) { |
2a4d2032 IT |
464 | dev_err(&client->dev, "Invalid buffer size %d\n", len); |
465 | return -EINVAL; | |
466 | } | |
40cb7613 | 467 | |
c0d901cc | 468 | for (i = 0; i < len; i++) |
40cb7613 IT |
469 | be_buf[i] = cpu_to_be16(buf[i]); |
470 | ||
471 | return mma9551_transfer(client, app_id, MMA9551_CMD_WRITE_CONFIG, | |
c0d901cc | 472 | reg, (u8 *)be_buf, len * sizeof(u16), NULL, 0); |
40cb7613 IT |
473 | } |
474 | EXPORT_SYMBOL(mma9551_write_config_words); | |
475 | ||
d5b97f5c IT |
476 | /** |
477 | * mma9551_update_config_bits() - update bits in register | |
478 | * @client: I2C client | |
479 | * @app_id: Application ID | |
480 | * @reg: Application register | |
481 | * @mask: Mask for the bits to update | |
482 | * @val: Value of the bits to update | |
483 | * | |
484 | * Update bits in the given register using a bit mask. | |
485 | * | |
486 | * Locking note: This function must be called with the device lock held. | |
487 | * Locking is not handled inside the function. Callers should ensure they | |
488 | * serialize access to the HW. | |
489 | * | |
490 | * Returns: 0 on success, negative value on failure. | |
491 | */ | |
492 | int mma9551_update_config_bits(struct i2c_client *client, u8 app_id, | |
493 | u16 reg, u8 mask, u8 val) | |
494 | { | |
495 | int ret; | |
496 | u8 tmp, orig; | |
497 | ||
498 | ret = mma9551_read_config_byte(client, app_id, reg, &orig); | |
499 | if (ret < 0) | |
500 | return ret; | |
501 | ||
502 | tmp = orig & ~mask; | |
503 | tmp |= val & mask; | |
504 | ||
505 | if (tmp == orig) | |
506 | return 0; | |
507 | ||
508 | return mma9551_write_config_byte(client, app_id, reg, tmp); | |
509 | } | |
510 | EXPORT_SYMBOL(mma9551_update_config_bits); | |
511 | ||
512 | /** | |
513 | * mma9551_gpio_config() - configure gpio | |
514 | * @client: I2C client | |
515 | * @pin: GPIO pin to configure | |
516 | * @app_id: Application ID | |
517 | * @bitnum: Bit number of status register being assigned to the GPIO pin. | |
518 | * @polarity: The polarity parameter is described in section 6.2.2, page 66, | |
519 | * of the Software Reference Manual. Basically, polarity=0 means | |
520 | * the interrupt line has the same value as the selected bit, | |
521 | * while polarity=1 means the line is inverted. | |
522 | * | |
523 | * Assign a bit from an application’s status register to a specific GPIO pin. | |
524 | * | |
525 | * Locking note: This function must be called with the device lock held. | |
526 | * Locking is not handled inside the function. Callers should ensure they | |
527 | * serialize access to the HW. | |
528 | * | |
529 | * Returns: 0 on success, negative value on failure. | |
530 | */ | |
531 | int mma9551_gpio_config(struct i2c_client *client, enum mma9551_gpio_pin pin, | |
532 | u8 app_id, u8 bitnum, int polarity) | |
533 | { | |
534 | u8 reg, pol_mask, pol_val; | |
535 | int ret; | |
536 | ||
537 | if (pin > mma9551_gpio_max) { | |
538 | dev_err(&client->dev, "bad GPIO pin\n"); | |
539 | return -EINVAL; | |
540 | } | |
541 | ||
542 | /* | |
543 | * Pin 6 is configured by regs 0x00 and 0x01, pin 7 by 0x02 and | |
544 | * 0x03, and so on. | |
545 | */ | |
546 | reg = pin * 2; | |
547 | ||
548 | ret = mma9551_write_config_byte(client, MMA9551_APPID_GPIO, | |
549 | reg, app_id); | |
550 | if (ret < 0) { | |
551 | dev_err(&client->dev, "error setting GPIO app_id\n"); | |
552 | return ret; | |
553 | } | |
554 | ||
555 | ret = mma9551_write_config_byte(client, MMA9551_APPID_GPIO, | |
556 | reg + 1, bitnum); | |
557 | if (ret < 0) { | |
558 | dev_err(&client->dev, "error setting GPIO bit number\n"); | |
559 | return ret; | |
560 | } | |
561 | ||
562 | switch (pin) { | |
563 | case mma9551_gpio6: | |
564 | reg = MMA9551_GPIO_POL_LSB; | |
565 | pol_mask = 1 << 6; | |
566 | break; | |
567 | case mma9551_gpio7: | |
568 | reg = MMA9551_GPIO_POL_LSB; | |
569 | pol_mask = 1 << 7; | |
570 | break; | |
571 | case mma9551_gpio8: | |
572 | reg = MMA9551_GPIO_POL_MSB; | |
573 | pol_mask = 1 << 0; | |
574 | break; | |
575 | case mma9551_gpio9: | |
576 | reg = MMA9551_GPIO_POL_MSB; | |
577 | pol_mask = 1 << 1; | |
578 | break; | |
579 | } | |
580 | pol_val = polarity ? pol_mask : 0; | |
581 | ||
582 | ret = mma9551_update_config_bits(client, MMA9551_APPID_GPIO, reg, | |
583 | pol_mask, pol_val); | |
584 | if (ret < 0) | |
585 | dev_err(&client->dev, "error setting GPIO polarity\n"); | |
586 | ||
587 | return ret; | |
588 | } | |
589 | EXPORT_SYMBOL(mma9551_gpio_config); | |
590 | ||
591 | /** | |
592 | * mma9551_read_version() - read device version information | |
593 | * @client: I2C client | |
594 | * | |
595 | * Read version information and print device id and firmware version. | |
596 | * | |
597 | * Locking note: This function must be called with the device lock held. | |
598 | * Locking is not handled inside the function. Callers should ensure they | |
599 | * serialize access to the HW. | |
600 | * | |
601 | * Returns: 0 on success, negative value on failure. | |
602 | */ | |
603 | int mma9551_read_version(struct i2c_client *client) | |
604 | { | |
605 | struct mma9551_version_info info; | |
606 | int ret; | |
607 | ||
608 | ret = mma9551_transfer(client, MMA9551_APPID_VERSION, 0x00, 0x00, | |
609 | NULL, 0, (u8 *)&info, sizeof(info)); | |
610 | if (ret < 0) | |
611 | return ret; | |
612 | ||
613 | dev_info(&client->dev, "device ID 0x%x, firmware version %02x.%02x\n", | |
614 | be32_to_cpu(info.device_id), info.fw_version[0], | |
615 | info.fw_version[1]); | |
616 | ||
617 | return 0; | |
618 | } | |
619 | EXPORT_SYMBOL(mma9551_read_version); | |
620 | ||
621 | /** | |
622 | * mma9551_set_device_state() - sets HW power mode | |
623 | * @client: I2C client | |
624 | * @enable: Use true to power on device, false to cause the device | |
625 | * to enter sleep. | |
626 | * | |
627 | * Set power on/off for device using the Sleep/Wake Application. | |
628 | * When enable is true, power on chip and enable doze mode. | |
629 | * When enable is false, enter sleep mode (device remains in the | |
630 | * lowest-power mode). | |
631 | * | |
632 | * Locking note: This function must be called with the device lock held. | |
633 | * Locking is not handled inside the function. Callers should ensure they | |
634 | * serialize access to the HW. | |
635 | * | |
636 | * Returns: 0 on success, negative value on failure. | |
637 | */ | |
638 | int mma9551_set_device_state(struct i2c_client *client, bool enable) | |
639 | { | |
640 | return mma9551_update_config_bits(client, MMA9551_APPID_SLEEP_WAKE, | |
641 | MMA9551_SLEEP_CFG, | |
642 | MMA9551_SLEEP_CFG_SNCEN | | |
643 | MMA9551_SLEEP_CFG_FLEEN | | |
644 | MMA9551_SLEEP_CFG_SCHEN, | |
645 | enable ? MMA9551_SLEEP_CFG_SCHEN | | |
646 | MMA9551_SLEEP_CFG_FLEEN : | |
647 | MMA9551_SLEEP_CFG_SNCEN); | |
648 | } | |
649 | EXPORT_SYMBOL(mma9551_set_device_state); | |
650 | ||
651 | /** | |
652 | * mma9551_set_power_state() - sets runtime PM state | |
653 | * @client: I2C client | |
654 | * @on: Use true to power on device, false to power off | |
655 | * | |
656 | * Resume or suspend the device using Runtime PM. | |
657 | * The device will suspend after the autosuspend delay. | |
658 | * | |
659 | * Returns: 0 on success, negative value on failure. | |
660 | */ | |
661 | int mma9551_set_power_state(struct i2c_client *client, bool on) | |
662 | { | |
663 | #ifdef CONFIG_PM | |
664 | int ret; | |
665 | ||
666 | if (on) | |
667 | ret = pm_runtime_get_sync(&client->dev); | |
668 | else { | |
669 | pm_runtime_mark_last_busy(&client->dev); | |
670 | ret = pm_runtime_put_autosuspend(&client->dev); | |
671 | } | |
672 | ||
673 | if (ret < 0) { | |
674 | dev_err(&client->dev, | |
675 | "failed to change power state to %d\n", on); | |
676 | if (on) | |
677 | pm_runtime_put_noidle(&client->dev); | |
678 | ||
679 | return ret; | |
680 | } | |
681 | #endif | |
682 | ||
683 | return 0; | |
684 | } | |
685 | EXPORT_SYMBOL(mma9551_set_power_state); | |
686 | ||
687 | /** | |
688 | * mma9551_sleep() - sleep | |
689 | * @freq: Application frequency | |
690 | * | |
691 | * Firmware applications run at a certain frequency on the | |
692 | * device. Sleep for one application cycle to make sure the | |
693 | * application had time to run once and initialize set values. | |
694 | */ | |
695 | void mma9551_sleep(int freq) | |
696 | { | |
697 | int sleep_val = 1000 / freq; | |
698 | ||
699 | if (sleep_val < 20) | |
700 | usleep_range(sleep_val * 1000, 20000); | |
701 | else | |
702 | msleep_interruptible(sleep_val); | |
703 | } | |
704 | EXPORT_SYMBOL(mma9551_sleep); | |
705 | ||
706 | /** | |
707 | * mma9551_read_accel_chan() - read accelerometer channel | |
708 | * @client: I2C client | |
709 | * @chan: IIO channel | |
710 | * @val: Pointer to the accelerometer value read | |
711 | * @val2: Unused | |
712 | * | |
713 | * Read accelerometer value for the specified channel. | |
714 | * | |
715 | * Locking note: This function must be called with the device lock held. | |
716 | * Locking is not handled inside the function. Callers should ensure they | |
717 | * serialize access to the HW. | |
718 | * | |
719 | * Returns: IIO_VAL_INT on success, negative value on failure. | |
720 | */ | |
721 | int mma9551_read_accel_chan(struct i2c_client *client, | |
722 | const struct iio_chan_spec *chan, | |
723 | int *val, int *val2) | |
724 | { | |
725 | u16 reg_addr; | |
726 | s16 raw_accel; | |
727 | int ret; | |
728 | ||
729 | switch (chan->channel2) { | |
730 | case IIO_MOD_X: | |
731 | reg_addr = MMA9551_AFE_X_ACCEL_REG; | |
732 | break; | |
733 | case IIO_MOD_Y: | |
734 | reg_addr = MMA9551_AFE_Y_ACCEL_REG; | |
735 | break; | |
736 | case IIO_MOD_Z: | |
737 | reg_addr = MMA9551_AFE_Z_ACCEL_REG; | |
738 | break; | |
739 | default: | |
740 | return -EINVAL; | |
741 | } | |
742 | ||
743 | ret = mma9551_set_power_state(client, true); | |
744 | if (ret < 0) | |
745 | return ret; | |
746 | ||
747 | ret = mma9551_read_status_word(client, MMA9551_APPID_AFE, | |
748 | reg_addr, &raw_accel); | |
749 | if (ret < 0) | |
750 | goto out_poweroff; | |
751 | ||
752 | *val = raw_accel; | |
753 | ||
754 | ret = IIO_VAL_INT; | |
755 | ||
756 | out_poweroff: | |
757 | mma9551_set_power_state(client, false); | |
758 | return ret; | |
759 | } | |
760 | EXPORT_SYMBOL(mma9551_read_accel_chan); | |
761 | ||
762 | /** | |
763 | * mma9551_read_accel_scale() - read accelerometer scale | |
764 | * @val: Pointer to the accelerometer scale (int value) | |
765 | * @val2: Pointer to the accelerometer scale (micro value) | |
766 | * | |
767 | * Read accelerometer scale. | |
768 | * | |
769 | * Returns: IIO_VAL_INT_PLUS_MICRO. | |
770 | */ | |
771 | int mma9551_read_accel_scale(int *val, int *val2) | |
772 | { | |
773 | *val = 0; | |
774 | *val2 = 2440; | |
775 | ||
776 | return IIO_VAL_INT_PLUS_MICRO; | |
777 | } | |
778 | EXPORT_SYMBOL(mma9551_read_accel_scale); | |
779 | ||
40cb7613 IT |
780 | /** |
781 | * mma9551_app_reset() - reset application | |
782 | * @client: I2C client | |
783 | * @app_mask: Application to reset | |
784 | * | |
785 | * Reset the given application (using the Reset/Suspend/Clear | |
786 | * Control Application) | |
787 | * | |
788 | * Returns: 0 on success, negative value on failure. | |
789 | */ | |
790 | int mma9551_app_reset(struct i2c_client *client, u32 app_mask) | |
791 | { | |
476c41a7 | 792 | return mma9551_write_config_byte(client, MMA9551_APPID_RSC, |
40cb7613 IT |
793 | MMA9551_RSC_RESET + |
794 | MMA9551_RSC_OFFSET(app_mask), | |
795 | MMA9551_RSC_VAL(app_mask)); | |
796 | } | |
797 | EXPORT_SYMBOL(mma9551_app_reset); | |
798 | ||
d5b97f5c IT |
799 | MODULE_AUTHOR("Irina Tirdea <irina.tirdea@intel.com>"); |
800 | MODULE_AUTHOR("Vlad Dogaru <vlad.dogaru@intel.com>"); | |
801 | MODULE_LICENSE("GPL v2"); | |
802 | MODULE_DESCRIPTION("MMA955xL sensors core"); |