diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-22 10:38:37 -0500 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-22 10:38:37 -0500 |
commit | fcc9d2e5a6c89d22b8b773a64fb4ad21ac318446 (patch) | |
tree | a57612d1888735a2ec7972891b68c1ac5ec8faea /drivers/misc/inv_mpu/mpu6050/mlsl-kernel.c | |
parent | 8dea78da5cee153b8af9c07a2745f6c55057fe12 (diff) |
Diffstat (limited to 'drivers/misc/inv_mpu/mpu6050/mlsl-kernel.c')
-rw-r--r-- | drivers/misc/inv_mpu/mpu6050/mlsl-kernel.c | 420 |
1 files changed, 420 insertions, 0 deletions
diff --git a/drivers/misc/inv_mpu/mpu6050/mlsl-kernel.c b/drivers/misc/inv_mpu/mpu6050/mlsl-kernel.c new file mode 100644 index 00000000000..f1c228f48fe --- /dev/null +++ b/drivers/misc/inv_mpu/mpu6050/mlsl-kernel.c | |||
@@ -0,0 +1,420 @@ | |||
1 | /* | ||
2 | $License: | ||
3 | Copyright (C) 2011 InvenSense Corporation, All Rights Reserved. | ||
4 | |||
5 | This program is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published by | ||
7 | the Free Software Foundation; either version 2 of the License, or | ||
8 | (at your option) any later version. | ||
9 | |||
10 | This program is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | GNU General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | $ | ||
18 | */ | ||
19 | |||
20 | #include "mlsl.h" | ||
21 | #include <linux/i2c.h> | ||
22 | #include "log.h" | ||
23 | #include "mpu6050b1.h" | ||
24 | |||
25 | static int inv_i2c_write(struct i2c_adapter *i2c_adap, | ||
26 | unsigned char address, | ||
27 | unsigned int len, unsigned char const *data) | ||
28 | { | ||
29 | struct i2c_msg msgs[1]; | ||
30 | int res; | ||
31 | |||
32 | if (!data || !i2c_adap) { | ||
33 | LOG_RESULT_LOCATION(-EINVAL); | ||
34 | return -EINVAL; | ||
35 | } | ||
36 | |||
37 | msgs[0].addr = address; | ||
38 | msgs[0].flags = 0; /* write */ | ||
39 | msgs[0].buf = (unsigned char *)data; | ||
40 | msgs[0].len = len; | ||
41 | |||
42 | res = i2c_transfer(i2c_adap, msgs, 1); | ||
43 | if (res < 1) { | ||
44 | if (res == 0) | ||
45 | res = -EIO; | ||
46 | LOG_RESULT_LOCATION(res); | ||
47 | return res; | ||
48 | } else | ||
49 | return 0; | ||
50 | } | ||
51 | |||
52 | static int inv_i2c_write_register(struct i2c_adapter *i2c_adap, | ||
53 | unsigned char address, | ||
54 | unsigned char reg, unsigned char value) | ||
55 | { | ||
56 | unsigned char data[2]; | ||
57 | |||
58 | data[0] = reg; | ||
59 | data[1] = value; | ||
60 | return inv_i2c_write(i2c_adap, address, 2, data); | ||
61 | } | ||
62 | |||
63 | static int inv_i2c_read(struct i2c_adapter *i2c_adap, | ||
64 | unsigned char address, unsigned char reg, | ||
65 | unsigned int len, unsigned char *data) | ||
66 | { | ||
67 | struct i2c_msg msgs[2]; | ||
68 | int res; | ||
69 | |||
70 | if (!data || !i2c_adap) { | ||
71 | LOG_RESULT_LOCATION(-EINVAL); | ||
72 | return -EINVAL; | ||
73 | } | ||
74 | |||
75 | msgs[0].addr = address; | ||
76 | msgs[0].flags = 0; /* write */ | ||
77 | msgs[0].buf = ® | ||
78 | msgs[0].len = 1; | ||
79 | |||
80 | msgs[1].addr = address; | ||
81 | msgs[1].flags = I2C_M_RD; | ||
82 | msgs[1].buf = data; | ||
83 | msgs[1].len = len; | ||
84 | |||
85 | res = i2c_transfer(i2c_adap, msgs, 2); | ||
86 | if (res < 2) { | ||
87 | if (res >= 0) | ||
88 | res = -EIO; | ||
89 | LOG_RESULT_LOCATION(res); | ||
90 | return res; | ||
91 | } else | ||
92 | return 0; | ||
93 | } | ||
94 | |||
95 | static int mpu_memory_read(struct i2c_adapter *i2c_adap, | ||
96 | unsigned char mpu_addr, | ||
97 | unsigned short mem_addr, | ||
98 | unsigned int len, unsigned char *data) | ||
99 | { | ||
100 | unsigned char bank[2]; | ||
101 | unsigned char addr[2]; | ||
102 | unsigned char buf; | ||
103 | |||
104 | struct i2c_msg msgs[4]; | ||
105 | int res; | ||
106 | |||
107 | if (!data || !i2c_adap) { | ||
108 | LOG_RESULT_LOCATION(-EINVAL); | ||
109 | return -EINVAL; | ||
110 | } | ||
111 | |||
112 | bank[0] = MPUREG_BANK_SEL; | ||
113 | bank[1] = mem_addr >> 8; | ||
114 | |||
115 | addr[0] = MPUREG_MEM_START_ADDR; | ||
116 | addr[1] = mem_addr & 0xFF; | ||
117 | |||
118 | buf = MPUREG_MEM_R_W; | ||
119 | |||
120 | /* write message */ | ||
121 | msgs[0].addr = mpu_addr; | ||
122 | msgs[0].flags = 0; | ||
123 | msgs[0].buf = bank; | ||
124 | msgs[0].len = sizeof(bank); | ||
125 | |||
126 | msgs[1].addr = mpu_addr; | ||
127 | msgs[1].flags = 0; | ||
128 | msgs[1].buf = addr; | ||
129 | msgs[1].len = sizeof(addr); | ||
130 | |||
131 | msgs[2].addr = mpu_addr; | ||
132 | msgs[2].flags = 0; | ||
133 | msgs[2].buf = &buf; | ||
134 | msgs[2].len = 1; | ||
135 | |||
136 | msgs[3].addr = mpu_addr; | ||
137 | msgs[3].flags = I2C_M_RD; | ||
138 | msgs[3].buf = data; | ||
139 | msgs[3].len = len; | ||
140 | |||
141 | res = i2c_transfer(i2c_adap, msgs, 4); | ||
142 | if (res != 4) { | ||
143 | if (res >= 0) | ||
144 | res = -EIO; | ||
145 | LOG_RESULT_LOCATION(res); | ||
146 | return res; | ||
147 | } else | ||
148 | return 0; | ||
149 | } | ||
150 | |||
151 | static int mpu_memory_write(struct i2c_adapter *i2c_adap, | ||
152 | unsigned char mpu_addr, | ||
153 | unsigned short mem_addr, | ||
154 | unsigned int len, unsigned char const *data) | ||
155 | { | ||
156 | unsigned char bank[2]; | ||
157 | unsigned char addr[2]; | ||
158 | unsigned char buf[513]; | ||
159 | |||
160 | struct i2c_msg msgs[3]; | ||
161 | int res; | ||
162 | |||
163 | if (!data || !i2c_adap) { | ||
164 | LOG_RESULT_LOCATION(-EINVAL); | ||
165 | return -EINVAL; | ||
166 | } | ||
167 | if (len >= (sizeof(buf) - 1)) { | ||
168 | LOG_RESULT_LOCATION(-ENOMEM); | ||
169 | return -ENOMEM; | ||
170 | } | ||
171 | |||
172 | bank[0] = MPUREG_BANK_SEL; | ||
173 | bank[1] = mem_addr >> 8; | ||
174 | |||
175 | addr[0] = MPUREG_MEM_START_ADDR; | ||
176 | addr[1] = mem_addr & 0xFF; | ||
177 | |||
178 | buf[0] = MPUREG_MEM_R_W; | ||
179 | memcpy(buf + 1, data, len); | ||
180 | |||
181 | /* write message */ | ||
182 | msgs[0].addr = mpu_addr; | ||
183 | msgs[0].flags = 0; | ||
184 | msgs[0].buf = bank; | ||
185 | msgs[0].len = sizeof(bank); | ||
186 | |||
187 | msgs[1].addr = mpu_addr; | ||
188 | msgs[1].flags = 0; | ||
189 | msgs[1].buf = addr; | ||
190 | msgs[1].len = sizeof(addr); | ||
191 | |||
192 | msgs[2].addr = mpu_addr; | ||
193 | msgs[2].flags = 0; | ||
194 | msgs[2].buf = (unsigned char *)buf; | ||
195 | msgs[2].len = len + 1; | ||
196 | |||
197 | res = i2c_transfer(i2c_adap, msgs, 3); | ||
198 | if (res != 3) { | ||
199 | if (res >= 0) | ||
200 | res = -EIO; | ||
201 | LOG_RESULT_LOCATION(res); | ||
202 | return res; | ||
203 | } else | ||
204 | return 0; | ||
205 | } | ||
206 | |||
207 | int inv_serial_single_write( | ||
208 | void *sl_handle, | ||
209 | unsigned char slave_addr, | ||
210 | unsigned char register_addr, | ||
211 | unsigned char data) | ||
212 | { | ||
213 | return inv_i2c_write_register((struct i2c_adapter *)sl_handle, | ||
214 | slave_addr, register_addr, data); | ||
215 | } | ||
216 | EXPORT_SYMBOL(inv_serial_single_write); | ||
217 | |||
218 | int inv_serial_write( | ||
219 | void *sl_handle, | ||
220 | unsigned char slave_addr, | ||
221 | unsigned short length, | ||
222 | unsigned char const *data) | ||
223 | { | ||
224 | int result; | ||
225 | const unsigned short data_length = length - 1; | ||
226 | const unsigned char start_reg_addr = data[0]; | ||
227 | unsigned char i2c_write[SERIAL_MAX_TRANSFER_SIZE + 1]; | ||
228 | unsigned short bytes_written = 0; | ||
229 | |||
230 | while (bytes_written < data_length) { | ||
231 | unsigned short this_len = min(SERIAL_MAX_TRANSFER_SIZE, | ||
232 | data_length - bytes_written); | ||
233 | if (bytes_written == 0) { | ||
234 | result = inv_i2c_write((struct i2c_adapter *) | ||
235 | sl_handle, slave_addr, | ||
236 | 1 + this_len, data); | ||
237 | } else { | ||
238 | /* manually increment register addr between chunks */ | ||
239 | i2c_write[0] = start_reg_addr + bytes_written; | ||
240 | memcpy(&i2c_write[1], &data[1 + bytes_written], | ||
241 | this_len); | ||
242 | result = inv_i2c_write((struct i2c_adapter *) | ||
243 | sl_handle, slave_addr, | ||
244 | 1 + this_len, i2c_write); | ||
245 | } | ||
246 | if (result) { | ||
247 | LOG_RESULT_LOCATION(result); | ||
248 | return result; | ||
249 | } | ||
250 | bytes_written += this_len; | ||
251 | } | ||
252 | return 0; | ||
253 | } | ||
254 | EXPORT_SYMBOL(inv_serial_write); | ||
255 | |||
256 | int inv_serial_read( | ||
257 | void *sl_handle, | ||
258 | unsigned char slave_addr, | ||
259 | unsigned char register_addr, | ||
260 | unsigned short length, | ||
261 | unsigned char *data) | ||
262 | { | ||
263 | int result; | ||
264 | unsigned short bytes_read = 0; | ||
265 | |||
266 | if ((slave_addr & 0x7E) == DEFAULT_MPU_SLAVEADDR | ||
267 | && (register_addr == MPUREG_FIFO_R_W || | ||
268 | register_addr == MPUREG_MEM_R_W)) { | ||
269 | LOG_RESULT_LOCATION(INV_ERROR_INVALID_PARAMETER); | ||
270 | return INV_ERROR_INVALID_PARAMETER; | ||
271 | } | ||
272 | |||
273 | while (bytes_read < length) { | ||
274 | unsigned short this_len = | ||
275 | min(SERIAL_MAX_TRANSFER_SIZE, length - bytes_read); | ||
276 | result = inv_i2c_read((struct i2c_adapter *)sl_handle, | ||
277 | slave_addr, register_addr + bytes_read, | ||
278 | this_len, &data[bytes_read]); | ||
279 | if (result) { | ||
280 | LOG_RESULT_LOCATION(result); | ||
281 | return result; | ||
282 | } | ||
283 | bytes_read += this_len; | ||
284 | } | ||
285 | return 0; | ||
286 | } | ||
287 | EXPORT_SYMBOL(inv_serial_read); | ||
288 | |||
289 | int inv_serial_write_mem( | ||
290 | void *sl_handle, | ||
291 | unsigned char slave_addr, | ||
292 | unsigned short mem_addr, | ||
293 | unsigned short length, | ||
294 | unsigned char const *data) | ||
295 | { | ||
296 | int result; | ||
297 | unsigned short bytes_written = 0; | ||
298 | |||
299 | if ((mem_addr & 0xFF) + length > MPU_MEM_BANK_SIZE) { | ||
300 | pr_err("memory read length (%d B) extends beyond its" | ||
301 | " limits (%d) if started at location %d\n", length, | ||
302 | MPU_MEM_BANK_SIZE, mem_addr & 0xFF); | ||
303 | return INV_ERROR_INVALID_PARAMETER; | ||
304 | } | ||
305 | while (bytes_written < length) { | ||
306 | unsigned short this_len = | ||
307 | min(SERIAL_MAX_TRANSFER_SIZE, length - bytes_written); | ||
308 | result = mpu_memory_write((struct i2c_adapter *)sl_handle, | ||
309 | slave_addr, mem_addr + bytes_written, | ||
310 | this_len, &data[bytes_written]); | ||
311 | if (result) { | ||
312 | LOG_RESULT_LOCATION(result); | ||
313 | return result; | ||
314 | } | ||
315 | bytes_written += this_len; | ||
316 | } | ||
317 | return 0; | ||
318 | } | ||
319 | EXPORT_SYMBOL(inv_serial_write_mem); | ||
320 | |||
321 | int inv_serial_read_mem( | ||
322 | void *sl_handle, | ||
323 | unsigned char slave_addr, | ||
324 | unsigned short mem_addr, | ||
325 | unsigned short length, | ||
326 | unsigned char *data) | ||
327 | { | ||
328 | int result; | ||
329 | unsigned short bytes_read = 0; | ||
330 | |||
331 | if ((mem_addr & 0xFF) + length > MPU_MEM_BANK_SIZE) { | ||
332 | printk | ||
333 | ("memory read length (%d B) extends beyond its limits (%d) " | ||
334 | "if started at location %d\n", length, | ||
335 | MPU_MEM_BANK_SIZE, mem_addr & 0xFF); | ||
336 | return INV_ERROR_INVALID_PARAMETER; | ||
337 | } | ||
338 | while (bytes_read < length) { | ||
339 | unsigned short this_len = | ||
340 | min(SERIAL_MAX_TRANSFER_SIZE, length - bytes_read); | ||
341 | result = | ||
342 | mpu_memory_read((struct i2c_adapter *)sl_handle, | ||
343 | slave_addr, mem_addr + bytes_read, | ||
344 | this_len, &data[bytes_read]); | ||
345 | if (result) { | ||
346 | LOG_RESULT_LOCATION(result); | ||
347 | return result; | ||
348 | } | ||
349 | bytes_read += this_len; | ||
350 | } | ||
351 | return 0; | ||
352 | } | ||
353 | EXPORT_SYMBOL(inv_serial_read_mem); | ||
354 | |||
355 | int inv_serial_write_fifo( | ||
356 | void *sl_handle, | ||
357 | unsigned char slave_addr, | ||
358 | unsigned short length, | ||
359 | unsigned char const *data) | ||
360 | { | ||
361 | int result; | ||
362 | unsigned char i2c_write[SERIAL_MAX_TRANSFER_SIZE + 1]; | ||
363 | unsigned short bytes_written = 0; | ||
364 | |||
365 | if (length > FIFO_HW_SIZE) { | ||
366 | printk(KERN_ERR | ||
367 | "maximum fifo write length is %d\n", FIFO_HW_SIZE); | ||
368 | return INV_ERROR_INVALID_PARAMETER; | ||
369 | } | ||
370 | while (bytes_written < length) { | ||
371 | unsigned short this_len = | ||
372 | min(SERIAL_MAX_TRANSFER_SIZE, length - bytes_written); | ||
373 | i2c_write[0] = MPUREG_FIFO_R_W; | ||
374 | memcpy(&i2c_write[1], &data[bytes_written], this_len); | ||
375 | result = inv_i2c_write((struct i2c_adapter *)sl_handle, | ||
376 | slave_addr, this_len + 1, i2c_write); | ||
377 | if (result) { | ||
378 | LOG_RESULT_LOCATION(result); | ||
379 | return result; | ||
380 | } | ||
381 | bytes_written += this_len; | ||
382 | } | ||
383 | return 0; | ||
384 | } | ||
385 | EXPORT_SYMBOL(inv_serial_write_fifo); | ||
386 | |||
387 | int inv_serial_read_fifo( | ||
388 | void *sl_handle, | ||
389 | unsigned char slave_addr, | ||
390 | unsigned short length, | ||
391 | unsigned char *data) | ||
392 | { | ||
393 | int result; | ||
394 | unsigned short bytes_read = 0; | ||
395 | |||
396 | if (length > FIFO_HW_SIZE) { | ||
397 | printk(KERN_ERR | ||
398 | "maximum fifo read length is %d\n", FIFO_HW_SIZE); | ||
399 | return INV_ERROR_INVALID_PARAMETER; | ||
400 | } | ||
401 | while (bytes_read < length) { | ||
402 | unsigned short this_len = | ||
403 | min(SERIAL_MAX_TRANSFER_SIZE, length - bytes_read); | ||
404 | result = inv_i2c_read((struct i2c_adapter *)sl_handle, | ||
405 | slave_addr, MPUREG_FIFO_R_W, this_len, | ||
406 | &data[bytes_read]); | ||
407 | if (result) { | ||
408 | LOG_RESULT_LOCATION(result); | ||
409 | return result; | ||
410 | } | ||
411 | bytes_read += this_len; | ||
412 | } | ||
413 | |||
414 | return 0; | ||
415 | } | ||
416 | EXPORT_SYMBOL(inv_serial_read_fifo); | ||
417 | |||
418 | /** | ||
419 | * @} | ||
420 | */ | ||