linux/drivers/iio/magnetometer/ak8974.c

// SPDX-License-Identifier: GPL-2.0-only
/*
 * Driver for the Asahi Kasei EMD Corporation AK8974
 * and Aichi Steel AMI305 magnetometer chips.
 * Based on a patch from Samu Onkalo and the AK8975 IIO driver.
 *
 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
 * Copyright (c) 2010 NVIDIA Corporation.
 * Copyright (C) 2016 Linaro Ltd.
 *
 * Author: Samu Onkalo <[email protected]>
 * Author: Linus Walleij <[email protected]>
 */
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/kernel.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/irq.h> /* For irq_get_irq_data() */
#include <linux/completion.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/delay.h>
#include <linux/bitops.h>
#include <linux/random.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/pm_runtime.h>

#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
#include <linux/iio/trigger.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>

/*
 * 16-bit registers are little-endian. LSB is at the address defined below
 * and MSB is at the next higher address.
 */

/* These registers are common for AK8974 and AMI30x */
#define AK8974_SELFTEST
#define AK8974_SELFTEST_IDLE
#define AK8974_SELFTEST_OK

#define AK8974_INFO

#define AK8974_WHOAMI
#define AK8974_WHOAMI_VALUE_AMI306
#define AK8974_WHOAMI_VALUE_AMI305
#define AK8974_WHOAMI_VALUE_AK8974
#define AK8974_WHOAMI_VALUE_HSCDTD008A

#define AK8974_DATA_X
#define AK8974_DATA_Y
#define AK8974_DATA_Z
#define AK8974_INT_SRC
#define AK8974_STATUS
#define AK8974_INT_CLEAR
#define AK8974_CTRL1
#define AK8974_CTRL2
#define AK8974_CTRL3
#define AK8974_INT_CTRL
#define AK8974_INT_THRES
#define AK8974_PRESET

/* AK8974-specific offsets */
#define AK8974_OFFSET_X
#define AK8974_OFFSET_Y
#define AK8974_OFFSET_Z
/* AMI305-specific offsets */
#define AMI305_OFFSET_X
#define AMI305_OFFSET_Y
#define AMI305_OFFSET_Z

/* Different temperature registers */
#define AK8974_TEMP
#define AMI305_TEMP

/* AMI306-specific control register */
#define AMI306_CTRL4

/* AMI306 factory calibration data */

/* fine axis sensitivity */
#define AMI306_FINEOUTPUT_X
#define AMI306_FINEOUTPUT_Y
#define AMI306_FINEOUTPUT_Z

/* axis sensitivity */
#define AMI306_SENS_X
#define AMI306_SENS_Y
#define AMI306_SENS_Z

/* axis cross-interference */
#define AMI306_GAIN_PARA_XZ
#define AMI306_GAIN_PARA_XY
#define AMI306_GAIN_PARA_YZ
#define AMI306_GAIN_PARA_YX
#define AMI306_GAIN_PARA_ZY
#define AMI306_GAIN_PARA_ZX

/* offset at ZERO magnetic field */
#define AMI306_OFFZERO_X
#define AMI306_OFFZERO_Y
#define AMI306_OFFZERO_Z


#define AK8974_INT_X_HIGH
#define AK8974_INT_Y_HIGH
#define AK8974_INT_Z_HIGH
#define AK8974_INT_X_LOW
#define AK8974_INT_Y_LOW
#define AK8974_INT_Z_LOW
#define AK8974_INT_RANGE

#define AK8974_STATUS_DRDY
#define AK8974_STATUS_OVERRUN
#define AK8974_STATUS_INT

#define AK8974_CTRL1_POWER
#define AK8974_CTRL1_RATE
#define AK8974_CTRL1_FORCE_EN
#define AK8974_CTRL1_MODE2

#define AK8974_CTRL2_INT_EN
#define AK8974_CTRL2_DRDY_EN
#define AK8974_CTRL2_DRDY_POL
#define AK8974_CTRL2_RESDEF

#define AK8974_CTRL3_RESET
#define AK8974_CTRL3_FORCE
#define AK8974_CTRL3_SELFTEST
#define AK8974_CTRL3_RESDEF

#define AK8974_INT_CTRL_XEN
#define AK8974_INT_CTRL_YEN
#define AK8974_INT_CTRL_ZEN
#define AK8974_INT_CTRL_XYZEN
#define AK8974_INT_CTRL_POL
#define AK8974_INT_CTRL_PULSE
#define AK8974_INT_CTRL_RESDEF

/* HSCDTD008A-specific control register */
#define HSCDTD008A_CTRL4
#define HSCDTD008A_CTRL4_MMD
#define HSCDTD008A_CTRL4_RANGE
#define HSCDTD008A_CTRL4_RESDEF

/* The AMI305 has elaborate FW version and serial number registers */
#define AMI305_VER
#define AMI305_SN

#define AK8974_MAX_RANGE

#define AK8974_POWERON_DELAY
#define AK8974_ACTIVATE_DELAY
#define AK8974_SELFTEST_DELAY
/*
 * Set the autosuspend to two orders of magnitude larger than the poweron
 * delay to make sane reasonable power tradeoff savings (5 seconds in
 * this case).
 */
#define AK8974_AUTOSUSPEND_DELAY

#define AK8974_MEASTIME

#define AK8974_PWR_ON
#define AK8974_PWR_OFF

/**
 * struct ak8974 - state container for the AK8974 driver
 * @i2c: parent I2C client
 * @orientation: mounting matrix, flipped axis etc
 * @map: regmap to access the AK8974 registers over I2C
 * @regs: the avdd and dvdd power regulators
 * @name: the name of the part
 * @variant: the whoami ID value (for selecting code paths)
 * @lock: locks the magnetometer for exclusive use during a measurement
 * @drdy_irq: uses the DRDY IRQ line
 * @drdy_complete: completion for DRDY
 * @drdy_active_low: the DRDY IRQ is active low
 * @scan: timestamps
 */
struct ak8974 {};

static const char ak8974_reg_avdd[] =;
static const char ak8974_reg_dvdd[] =;

static int ak8974_get_u16_val(struct ak8974 *ak8974, u8 reg, u16 *val)
{}

static int ak8974_set_u16_val(struct ak8974 *ak8974, u8 reg, u16 val)
{}

static int ak8974_set_power(struct ak8974 *ak8974, bool mode)
{}

static int ak8974_reset(struct ak8974 *ak8974)
{}

static int ak8974_configure(struct ak8974 *ak8974)
{}

static int ak8974_trigmeas(struct ak8974 *ak8974)
{}

static int ak8974_await_drdy(struct ak8974 *ak8974)
{}

static int ak8974_getresult(struct ak8974 *ak8974, __le16 *result)
{}

static irqreturn_t ak8974_drdy_irq(int irq, void *d)
{}

static irqreturn_t ak8974_drdy_irq_thread(int irq, void *d)
{}

static int ak8974_selftest(struct ak8974 *ak8974)
{}

static void ak8974_read_calib_data(struct ak8974 *ak8974, unsigned int reg,
				   __le16 *tab, size_t tab_size)
{}

static int ak8974_detect(struct ak8974 *ak8974)
{}

static int ak8974_measure_channel(struct ak8974 *ak8974, unsigned long address,
				  int *val)
{}

static int ak8974_read_raw(struct iio_dev *indio_dev,
			   struct iio_chan_spec const *chan,
			   int *val, int *val2,
			   long mask)
{}

static void ak8974_fill_buffer(struct iio_dev *indio_dev)
{}

static irqreturn_t ak8974_handle_trigger(int irq, void *p)
{}

static const struct iio_mount_matrix *
ak8974_get_mount_matrix(const struct iio_dev *indio_dev,
			const struct iio_chan_spec *chan)
{}

static const struct iio_chan_spec_ext_info ak8974_ext_info[] =;

#define AK8974_AXIS_CHANNEL(axis, index, bits)

/*
 * We have no datasheet for the AK8974 but we guess that its
 * ADC is 12 bits. The AMI305 and AMI306 certainly has 12bit
 * ADC.
 */
static const struct iio_chan_spec ak8974_12_bits_channels[] =;

/*
 * The HSCDTD008A has 15 bits resolution the way we set it up
 * in CTRL4.
 */
static const struct iio_chan_spec ak8974_15_bits_channels[] =;

static const unsigned long ak8974_scan_masks[] =;

static const struct iio_info ak8974_info =;

static bool ak8974_writeable_reg(struct device *dev, unsigned int reg)
{}

static bool ak8974_precious_reg(struct device *dev, unsigned int reg)
{}

static const struct regmap_config ak8974_regmap_config =;

static int ak8974_probe(struct i2c_client *i2c)
{}

static void ak8974_remove(struct i2c_client *i2c)
{}

static int ak8974_runtime_suspend(struct device *dev)
{}

static int ak8974_runtime_resume(struct device *dev)
{}

static DEFINE_RUNTIME_DEV_PM_OPS(ak8974_dev_pm_ops, ak8974_runtime_suspend,
				 ak8974_runtime_resume, NULL);

static const struct i2c_device_id ak8974_id[] =;
MODULE_DEVICE_TABLE(i2c, ak8974_id);

static const struct of_device_id ak8974_of_match[] =;
MODULE_DEVICE_TABLE(of, ak8974_of_match);

static struct i2c_driver ak8974_driver =;
module_i2c_driver();

MODULE_DESCRIPTION();
MODULE_AUTHOR();
MODULE_AUTHOR();
MODULE_LICENSE();