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 
25 static 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  */
AKD_InitDevice(void)35 int16_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  */
AKD_DeinitDevice(void)53 void 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  */
AKD_TxData(const BYTE address,const BYTE * data,const uint16_t numberOfBytesToWrite)76 int16_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  */
AKD_RxData(const BYTE address,BYTE * data,const uint16_t numberOfBytesToRead)127 int16_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  */
AKD_GetMagneticData(BYTE data[SENSOR_DATA_SIZE])175 int16_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  */
AKD_SetYPR(const int buf[YPR_DATA_SIZE])200 void 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  */
AKD_GetOpenStatus(int * status)213 int 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  */
AKD_GetCloseStatus(int * status)228 int 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  */
AKD_SetMode(const BYTE mode)248 int16_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  */
AKD_GetDelay(int64_t delay[AKM_NUM_SENSORS])269 int16_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  */
AKD_GetLayout(int16_t * layout)285 int16_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. */
AKD_GetAccelerationData(int16_t data[3])304 int16_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