sensor: add driver for AK8975 magnetometer
Add driver for the AK8975 3-axis electonic compass. Datasheet: http://www.akm.com/akm/en/file/datasheet/AK8975.pdf Change-Id: I427f954396c8991a153e4447d746b855d19cb60d Origin: Original Signed-off-by: Bogdan Davidoaia <bogdan.m.davidoaia@intel.com>
This commit is contained in:
parent
01062d97aa
commit
c4c01a92f3
|
@ -23,6 +23,8 @@ menuconfig SENSOR
|
|||
help
|
||||
Include sensor drivers in system config
|
||||
|
||||
source "drivers/sensor/Kconfig.ak8975"
|
||||
|
||||
source "drivers/sensor/Kconfig.bma280"
|
||||
|
||||
source "drivers/sensor/Kconfig.bmc150_magn"
|
||||
|
|
77
drivers/sensor/Kconfig.ak8975
Normal file
77
drivers/sensor/Kconfig.ak8975
Normal file
|
@ -0,0 +1,77 @@
|
|||
# Kconfig.ak8975 - AK8975 magnetometer configuration options
|
||||
|
||||
#
|
||||
# Copyright (c) 2016 Intel Corporation
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
menuconfig AK8975
|
||||
bool
|
||||
prompt "AK8975 Magnetometer"
|
||||
depends on SENSOR && I2C
|
||||
default n
|
||||
help
|
||||
Enable driver for AK8975 magnetometer.
|
||||
|
||||
config AK8975_SYS_LOG_LEVEL
|
||||
int "AK8975 Log level"
|
||||
depends on SYS_LOG && AK8975
|
||||
default 0
|
||||
range 0 4
|
||||
help
|
||||
Sets log level for AK8975 driver.
|
||||
Levels are:
|
||||
0 OFF, do not write
|
||||
1 ERROR, only write SYS_LOG_ERR
|
||||
2 WARNING, write SYS_LOG_WRN in addition to previous level
|
||||
3 INFO, write SYS_LOG_INF in addition to previous levels
|
||||
4 DEBUG, write SYS_LOG_DBG in addition to previous levels
|
||||
|
||||
config AK8975_NAME
|
||||
string
|
||||
prompt "Driver name"
|
||||
default "AK8975"
|
||||
depends on AK8975
|
||||
help
|
||||
Device name with which the AK8975 sensor is identified.
|
||||
|
||||
config AK8975_INIT_PRIORITY
|
||||
int
|
||||
prompt "Init priority"
|
||||
depends on AK8975
|
||||
default 70
|
||||
help
|
||||
Device driver initialization priority.
|
||||
|
||||
config AK8975_I2C_ADDR
|
||||
hex
|
||||
prompt "I2C address"
|
||||
depends on AK8975
|
||||
default 0x0C
|
||||
range 0x0C 0x0F
|
||||
help
|
||||
I2C address of the AK8975 sensor. Choose:
|
||||
- 0x0C if CAD1 connected to GND nad CAD0 is connected to GND
|
||||
- 0x0D if CAD1 connected to GND nad CAD0 is connected to VDD
|
||||
- 0x0E if CAD1 connected to VDD nad CAD0 is connected to GND
|
||||
- 0x0F if CAD1 connected to VDD nad CAD0 is connected to VDD
|
||||
|
||||
config AK8975_I2C_MASTER_DEV_NAME
|
||||
string
|
||||
prompt "I2C master where AK8975 is connected"
|
||||
depends on AK8975
|
||||
default "I2C_0"
|
||||
help
|
||||
Specify the device name of the I2C master device to which the
|
||||
AK8975 chip is connected.
|
|
@ -1,5 +1,6 @@
|
|||
ccflags-y +=-I$(srctree)/drivers
|
||||
|
||||
obj-$(CONFIG_AK8975) += sensor_ak8975.o
|
||||
obj-$(CONFIG_BMA280) += sensor_bma280.o
|
||||
obj-$(CONFIG_BMA280_TRIGGER) += sensor_bma280_trigger.o
|
||||
obj-$(CONFIG_BMC150_MAGN) += sensor_bmc150_magn.o
|
||||
|
|
155
drivers/sensor/sensor_ak8975.c
Normal file
155
drivers/sensor/sensor_ak8975.c
Normal file
|
@ -0,0 +1,155 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Intel Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <device.h>
|
||||
#include <i2c.h>
|
||||
#include <nanokernel.h>
|
||||
#include <sensor.h>
|
||||
#include <misc/__assert.h>
|
||||
#include <misc/byteorder.h>
|
||||
#include <misc/util.h>
|
||||
|
||||
#include "sensor_ak8975.h"
|
||||
|
||||
static int ak8975_sample_fetch(struct device *dev, enum sensor_channel chan)
|
||||
{
|
||||
struct ak8975_data *drv_data = dev->driver_data;
|
||||
uint8_t buf[6];
|
||||
|
||||
__ASSERT(chan == SENSOR_CHAN_ALL);
|
||||
|
||||
if (i2c_reg_write_byte(drv_data->i2c, CONFIG_AK8975_I2C_ADDR,
|
||||
AK8975_REG_CNTL, AK8975_MODE_MEASURE) < 0) {
|
||||
SYS_LOG_ERR("Failed to start measurement.");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
sys_thread_busy_wait(AK8975_MEASURE_TIME_US);
|
||||
|
||||
if (i2c_burst_read(drv_data->i2c, CONFIG_AK8975_I2C_ADDR,
|
||||
AK8975_REG_DATA_START, buf, 6) < 0) {
|
||||
SYS_LOG_ERR("Failed to read sample data.");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
drv_data->x_sample = sys_le16_to_cpu(buf[0] | (buf[1] << 8));
|
||||
drv_data->y_sample = sys_le16_to_cpu(buf[2] | (buf[3] << 8));
|
||||
drv_data->z_sample = sys_le16_to_cpu(buf[4] | (buf[5] << 8));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ak8975_convert(struct sensor_value *val, int16_t sample,
|
||||
uint8_t adjustment)
|
||||
{
|
||||
int32_t conv_val;
|
||||
|
||||
conv_val = sample * AK8975_MICRO_GAUSS_PER_BIT *
|
||||
((uint16_t)adjustment + 128) / 256;
|
||||
val->type = SENSOR_VALUE_TYPE_INT_PLUS_MICRO;
|
||||
val->val1 = conv_val / 1000000;
|
||||
val->val2 = conv_val % 1000000;
|
||||
}
|
||||
|
||||
static int ak8975_channel_get(struct device *dev,
|
||||
enum sensor_channel chan,
|
||||
struct sensor_value *val)
|
||||
{
|
||||
struct ak8975_data *drv_data = dev->driver_data;
|
||||
|
||||
__ASSERT(chan == SENSOR_CHAN_MAGN_ANY || chan == SENSOR_CHAN_MAGN_X ||
|
||||
chan == SENSOR_CHAN_MAGN_Y || chan == SENSOR_CHAN_MAGN_Z);
|
||||
|
||||
if (chan == SENSOR_CHAN_MAGN_ANY) {
|
||||
ak8975_convert(val, drv_data->x_sample, drv_data->x_adj);
|
||||
ak8975_convert(val + 1, drv_data->y_sample, drv_data->y_adj);
|
||||
ak8975_convert(val + 2, drv_data->z_sample, drv_data->z_adj);
|
||||
} else if (chan == SENSOR_CHAN_MAGN_X) {
|
||||
ak8975_convert(val, drv_data->x_sample, drv_data->x_adj);
|
||||
} else if (chan == SENSOR_CHAN_MAGN_Y) {
|
||||
ak8975_convert(val, drv_data->y_sample, drv_data->y_adj);
|
||||
} else { /* chan == SENSOR_CHAN_MAGN_Z */
|
||||
ak8975_convert(val, drv_data->z_sample, drv_data->z_adj);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct sensor_driver_api ak8975_driver_api = {
|
||||
.sample_fetch = ak8975_sample_fetch,
|
||||
.channel_get = ak8975_channel_get,
|
||||
};
|
||||
|
||||
static int ak8975_read_adjustment_data(struct ak8975_data *drv_data)
|
||||
{
|
||||
uint8_t buf[3];
|
||||
|
||||
if (i2c_reg_write_byte(drv_data->i2c, CONFIG_AK8975_I2C_ADDR,
|
||||
AK8975_REG_CNTL, AK8975_MODE_FUSE_ACCESS) < 0) {
|
||||
SYS_LOG_ERR("Failed to set chip in fuse access mode.");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (i2c_burst_read(drv_data->i2c, CONFIG_AK8975_I2C_ADDR,
|
||||
AK8975_REG_ADJ_DATA_START, buf, 3) < 0) {
|
||||
SYS_LOG_ERR("Failed to read adjustment data.");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
drv_data->x_adj = buf[0];
|
||||
drv_data->y_adj = buf[1];
|
||||
drv_data->z_adj = buf[2];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ak8975_init(struct device *dev)
|
||||
{
|
||||
struct ak8975_data *drv_data = dev->driver_data;
|
||||
uint8_t id;
|
||||
|
||||
drv_data->i2c = device_get_binding(CONFIG_AK8975_I2C_MASTER_DEV_NAME);
|
||||
if (drv_data->i2c == NULL) {
|
||||
SYS_LOG_ERR("Failed to get pointer to %s device!",
|
||||
CONFIG_AK8975_I2C_MASTER_DEV_NAME);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* check chip ID */
|
||||
if (i2c_reg_read_byte(drv_data->i2c, CONFIG_AK8975_I2C_ADDR,
|
||||
AK8975_REG_CHIP_ID, &id) < 0) {
|
||||
SYS_LOG_ERR("Failed to read chip ID.");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (id != AK8975_CHIP_ID) {
|
||||
SYS_LOG_ERR("Invalid chip ID.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (ak8975_read_adjustment_data(drv_data) < 0) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
dev->driver_api = &ak8975_driver_api;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct ak8975_data ak8975_data;
|
||||
|
||||
DEVICE_INIT(ak8975, CONFIG_AK8975_NAME, ak8975_init, &ak8975_data,
|
||||
NULL, SECONDARY, CONFIG_AK8975_INIT_PRIORITY);
|
52
drivers/sensor/sensor_ak8975.h
Normal file
52
drivers/sensor/sensor_ak8975.h
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Intel Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef __SENSOR_AK8975__
|
||||
#define __SENSOR_AK8975__
|
||||
|
||||
#include <device.h>
|
||||
|
||||
#define SYS_LOG_DOMAIN "AK8975"
|
||||
#define SYS_LOG_LEVEL CONFIG_AK8975_SYS_LOG_LEVEL
|
||||
#include <misc/sys_log.h>
|
||||
|
||||
#define AK8975_REG_CHIP_ID 0x00
|
||||
#define AK8975_CHIP_ID 0x48
|
||||
|
||||
#define AK8975_REG_DATA_START 0x03
|
||||
|
||||
#define AK8975_REG_CNTL 0x0A
|
||||
#define AK8975_MODE_MEASURE 0x01
|
||||
#define AK8975_MODE_FUSE_ACCESS 0x0F
|
||||
|
||||
#define AK8975_REG_ADJ_DATA_START 0x10
|
||||
|
||||
#define AK8975_MEASURE_TIME_US 9000
|
||||
#define AK8975_MICRO_GAUSS_PER_BIT 3000
|
||||
|
||||
struct ak8975_data {
|
||||
struct device *i2c;
|
||||
|
||||
int16_t x_sample;
|
||||
int16_t y_sample;
|
||||
int16_t z_sample;
|
||||
|
||||
uint8_t x_adj;
|
||||
uint8_t y_adj;
|
||||
uint8_t z_adj;
|
||||
};
|
||||
|
||||
#endif /* __SENSOR_AK8975__ */
|
Loading…
Reference in a new issue