1/******************************************************************************
2 * $Id: AK8975Driver.c 580 2012-03-29 09:56:21Z yamada.rj $
3 ******************************************************************************
4 *
5 * Copyright (C) 2012 Asahi Kasei Microdevices Corporation, Japan
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 *      http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19#include <fcntl.h>
20#include "AKFS_Common.h"
21#include "AK8975Driver.h"
22
23#define MSENSOR_NAME		"/dev/akm8975_dev"
24
25static int s_fdDev = -1;
26
27/*!
28 Open device driver.
29 This function opens both device drivers of magnetic sensor and acceleration
30 sensor. Additionally, some initial hardware settings are done, such as
31 measurement range, built-in filter function and etc.
32 @return If this function succeeds, the return value is #AKD_SUCCESS.
33 Otherwise the return value is #AKD_FAIL.
34 */
35int16_t AKD_InitDevice(void)
36{
37	if (s_fdDev < 0) {
38		/* Open magnetic sensor's device driver. */
39		if ((s_fdDev = open(MSENSOR_NAME, O_RDWR)) < 0) {
40			AKMERROR_STR("open");
41			return AKD_FAIL;
42		}
43	}
44
45	return AKD_SUCCESS;
46}
47
48/*!
49 Close device driver.
50 This function closes both device drivers of magnetic sensor and acceleration
51 sensor.
52 */
53void AKD_DeinitDevice(void)
54{
55	if (s_fdDev >= 0) {
56		close(s_fdDev);
57		s_fdDev = -1;
58	}
59}
60
61/*!
62 Writes data to a register of the AK8975.  When more than one byte of data is
63 specified, the data is written in contiguous locations starting at an address
64 specified in \a address.
65 @return If this function succeeds, the return value is #AKD_SUCCESS. Otherwise
66 the return value is #AKD_FAIL.
67 @param[in] address Specify the address of a register in which data is to be
68 written.
69 @param[in] data Specify data to write or a pointer to a data array containing
70 the data.  When specifying more than one byte of data, specify the starting
71 address of the array.
72 @param[in] numberOfBytesToWrite Specify the number of bytes that make up the
73 data to write.  When a pointer to an array is specified in data, this argument
74 equals the number of elements of the array.
75 */
76int16_t AKD_TxData(
77				const BYTE address,
78				const BYTE * data,
79				const uint16_t numberOfBytesToWrite)
80{
81	int i;
82	char buf[RWBUF_SIZE];
83
84	if (s_fdDev < 0) {
85		ALOGE("%s: Device file is not opened.", __FUNCTION__);
86		return AKD_FAIL;
87	}
88	if (numberOfBytesToWrite > (RWBUF_SIZE-2)) {
89		ALOGE("%s: Tx size is too large.", __FUNCTION__);
90		return AKD_FAIL;
91	}
92
93	buf[0] = numberOfBytesToWrite + 1;
94	buf[1] = address;
95
96	for (i = 0; i < numberOfBytesToWrite; i++) {
97		buf[i + 2] = data[i];
98	}
99	if (ioctl(s_fdDev, ECS_IOCTL_WRITE, buf) < 0) {
100		AKMERROR_STR("ioctl");
101		return AKD_FAIL;
102	} else {
103
104#if ENABLE_AKMDEBUG
105		AKMDATA(AKMDATA_DRV, "addr(HEX)=%02x data(HEX)=", address);
106		for (i = 0; i < numberOfBytesToWrite; i++) {
107			AKMDATA(AKMDATA_DRV, " %02x", data[i]);
108		}
109		AKMDATA(AKMDATA_DRV, "\n");
110#endif
111		return AKD_SUCCESS;
112	}
113}
114
115/*!
116 Acquires data from a register or the EEPROM of the AK8975.
117 @return If this function succeeds, the return value is #AKD_SUCCESS. Otherwise
118 the return value is #AKD_FAIL.
119 @param[in] address Specify the address of a register from which data is to be
120 read.
121 @param[out] data Specify a pointer to a data array which the read data are
122 stored.
123 @param[in] numberOfBytesToRead Specify the number of bytes that make up the
124 data to read.  When a pointer to an array is specified in data, this argument
125 equals the number of elements of the array.
126 */
127int16_t AKD_RxData(
128				const BYTE address,
129				BYTE * data,
130				const uint16_t numberOfBytesToRead)
131{
132	int i;
133	char buf[RWBUF_SIZE];
134
135	memset(data, 0, numberOfBytesToRead);
136
137	if (s_fdDev < 0) {
138		ALOGE("%s: Device file is not opened.", __FUNCTION__);
139		return AKD_FAIL;
140	}
141	if (numberOfBytesToRead > (RWBUF_SIZE-1)) {
142		ALOGE("%s: Rx size is too large.", __FUNCTION__);
143		return AKD_FAIL;
144	}
145
146	buf[0] = numberOfBytesToRead;
147	buf[1] = address;
148
149	if (ioctl(s_fdDev, ECS_IOCTL_READ, buf) < 0) {
150		AKMERROR_STR("ioctl");
151		return AKD_FAIL;
152	} else {
153		for (i = 0; i < numberOfBytesToRead; i++) {
154			data[i] = buf[i + 1];
155		}
156#if ENABLE_AKMDEBUG
157		AKMDATA(AKMDATA_DRV, "addr(HEX)=%02x len=%d data(HEX)=",
158				address, numberOfBytesToRead);
159		for (i = 0; i < numberOfBytesToRead; i++) {
160			AKMDATA(AKMDATA_DRV, " %02x", data[i]);
161		}
162		AKMDATA(AKMDATA_DRV, "\n");
163#endif
164		return AKD_SUCCESS;
165	}
166}
167
168/*!
169 Acquire magnetic data from AK8975. If measurement is not done, this function
170 waits until measurement completion.
171 @return If this function succeeds, the return value is #AKD_SUCCESS. Otherwise
172 the return value is #AKD_FAIL.
173 @param[out] data A magnetic data array. The size should be larger than #SENSOR_DATA_SIZE.
174 */
175int16_t AKD_GetMagneticData(BYTE data[SENSOR_DATA_SIZE])
176{
177	memset(data, 0, SENSOR_DATA_SIZE);
178
179	if (s_fdDev < 0) {
180		ALOGE("%s: Device file is not opened.", __FUNCTION__);
181		return AKD_FAIL;
182	}
183
184	if (ioctl(s_fdDev, ECS_IOCTL_GETDATA, data) < 0) {
185		AKMERROR_STR("ioctl");
186		return AKD_FAIL;
187	}
188
189	AKMDATA(AKMDATA_DRV,
190		"bdata(HEX)= %02x %02x %02x %02x %02x %02x %02x %02x\n",
191		data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]);
192
193	return AKD_SUCCESS;
194}
195
196/*!
197 Set calculated data to device driver.
198 @param[in] buf The order of input data depends on driver's specification.
199 */
200void AKD_SetYPR(const int buf[YPR_DATA_SIZE])
201{
202	if (s_fdDev < 0) {
203		ALOGE("%s: Device file is not opened.", __FUNCTION__);
204	} else {
205		if (ioctl(s_fdDev, ECS_IOCTL_SET_YPR, buf) < 0) {
206			AKMERROR_STR("ioctl");
207		}
208	}
209}
210
211/*!
212 */
213int AKD_GetOpenStatus(int* status)
214{
215	if (s_fdDev < 0) {
216		ALOGE("%s: Device file is not opened.", __FUNCTION__);
217		return AKD_FAIL;
218	}
219	if (ioctl(s_fdDev, ECS_IOCTL_GET_OPEN_STATUS, status) < 0) {
220		AKMERROR_STR("ioctl");
221		return AKD_FAIL;
222	}
223	return AKD_SUCCESS;
224}
225
226/*!
227 */
228int AKD_GetCloseStatus(int* status)
229{
230	if (s_fdDev < 0) {
231		ALOGE("%s: Device file is not opened.", __FUNCTION__);
232		return AKD_FAIL;
233	}
234	if (ioctl(s_fdDev, ECS_IOCTL_GET_CLOSE_STATUS, status) < 0) {
235		AKMERROR_STR("ioctl");
236		return AKD_FAIL;
237	}
238	return AKD_SUCCESS;
239}
240
241/*!
242 Set AK8975 to the specific mode.
243 @return If this function succeeds, the return value is #AKD_SUCCESS. Otherwise
244 the return value is #AKD_FAIL.
245 @param[in] mode This value should be one of the AK8975_Mode which is defined in
246 akm8975.h file.
247 */
248int16_t AKD_SetMode(const BYTE mode)
249{
250	if (s_fdDev < 0) {
251		ALOGE("%s: Device file is not opened.", __FUNCTION__);
252		return AKD_FAIL;
253	}
254
255	if (ioctl(s_fdDev, ECS_IOCTL_SET_MODE, &mode) < 0) {
256		AKMERROR_STR("ioctl");
257		return AKD_FAIL;
258	}
259
260	return AKD_SUCCESS;
261}
262
263/*!
264 Acquire delay
265 @return If this function succeeds, the return value is #AKD_SUCCESS. Otherwise
266 the return value is #AKD_FAIL.
267 @param[out] delay A delay in nanosecond.
268 */
269int16_t AKD_GetDelay(int64_t delay[AKM_NUM_SENSORS])
270{
271	if (s_fdDev < 0) {
272		ALOGE("%s: Device file is not opened.\n", __FUNCTION__);
273		return AKD_FAIL;
274	}
275	if (ioctl(s_fdDev, ECS_IOCTL_GET_DELAY, delay) < 0) {
276		AKMERROR_STR("ioctl");
277		return AKD_FAIL;
278	}
279	return AKD_SUCCESS;
280}
281
282/*!
283 Get layout information from device driver, i.e. platform data.
284 */
285int16_t AKD_GetLayout(int16_t* layout)
286{
287	char tmp;
288
289	if (s_fdDev < 0) {
290		ALOGE("%s: Device file is not opened.", __FUNCTION__);
291		return AKD_FAIL;
292	}
293
294	if (ioctl(s_fdDev, ECS_IOCTL_GET_LAYOUT, &tmp) < 0) {
295		AKMERROR_STR("ioctl");
296		return AKD_FAIL;
297	}
298
299	*layout = tmp;
300	return AKD_SUCCESS;
301}
302
303/* Get acceleration data. */
304int16_t AKD_GetAccelerationData(int16_t data[3])
305{
306	if (s_fdDev < 0) {
307		ALOGE("%s: Device file is not opened.", __FUNCTION__);
308		return AKD_FAIL;
309	}
310	if (ioctl(s_fdDev, ECS_IOCTL_GET_ACCEL, data) < 0) {
311		AKMERROR_STR("ioctl");
312		return AKD_FAIL;
313	}
314
315	AKMDATA(AKMDATA_DRV, "%s: acc=%d, %d, %d\n",
316			__FUNCTION__, data[0], data[1], data[2]);
317
318	return AKD_SUCCESS;
319}
320