linux/drivers/iio/magnetometer/ak8975.c

// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * A sensor driver for the magnetometer AK8975.
 *
 * Magnetic compass sensor driver for monitoring magnetic flux information.
 *
 * Copyright (c) 2010, NVIDIA Corporation.
 */

#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/delay.h>
#include <linux/bitops.h>
#include <linux/gpio/consumer.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>

/*
 * Register definitions, as well as various shifts and masks to get at the
 * individual fields of the registers.
 */
#define AK8975_REG_WIA
#define AK8975_DEVICE_ID

#define AK8975_REG_INFO

#define AK8975_REG_ST1
#define AK8975_REG_ST1_DRDY_SHIFT
#define AK8975_REG_ST1_DRDY_MASK

#define AK8975_REG_HXL
#define AK8975_REG_HXH
#define AK8975_REG_HYL
#define AK8975_REG_HYH
#define AK8975_REG_HZL
#define AK8975_REG_HZH
#define AK8975_REG_ST2
#define AK8975_REG_ST2_DERR_SHIFT
#define AK8975_REG_ST2_DERR_MASK

#define AK8975_REG_ST2_HOFL_SHIFT
#define AK8975_REG_ST2_HOFL_MASK

#define AK8975_REG_CNTL
#define AK8975_REG_CNTL_MODE_SHIFT
#define AK8975_REG_CNTL_MODE_MASK
#define AK8975_REG_CNTL_MODE_POWER_DOWN
#define AK8975_REG_CNTL_MODE_ONCE
#define AK8975_REG_CNTL_MODE_SELF_TEST
#define AK8975_REG_CNTL_MODE_FUSE_ROM

#define AK8975_REG_RSVC
#define AK8975_REG_ASTC
#define AK8975_REG_TS1
#define AK8975_REG_TS2
#define AK8975_REG_I2CDIS
#define AK8975_REG_ASAX
#define AK8975_REG_ASAY
#define AK8975_REG_ASAZ

#define AK8975_MAX_REGS

/*
 * AK09912 Register definitions
 */
#define AK09912_REG_WIA1
#define AK09912_REG_WIA2
#define AK09918_DEVICE_ID
#define AK09916_DEVICE_ID
#define AK09912_DEVICE_ID
#define AK09911_DEVICE_ID

#define AK09911_REG_INFO1
#define AK09911_REG_INFO2

#define AK09912_REG_ST1

#define AK09912_REG_ST1_DRDY_SHIFT
#define AK09912_REG_ST1_DRDY_MASK

#define AK09912_REG_HXL
#define AK09912_REG_HXH
#define AK09912_REG_HYL
#define AK09912_REG_HYH
#define AK09912_REG_HZL
#define AK09912_REG_HZH
#define AK09912_REG_TMPS

#define AK09912_REG_ST2
#define AK09912_REG_ST2_HOFL_SHIFT
#define AK09912_REG_ST2_HOFL_MASK

#define AK09912_REG_CNTL1

#define AK09912_REG_CNTL2
#define AK09912_REG_CNTL_MODE_POWER_DOWN
#define AK09912_REG_CNTL_MODE_ONCE
#define AK09912_REG_CNTL_MODE_SELF_TEST
#define AK09912_REG_CNTL_MODE_FUSE_ROM
#define AK09912_REG_CNTL2_MODE_SHIFT
#define AK09912_REG_CNTL2_MODE_MASK

#define AK09912_REG_CNTL3

#define AK09912_REG_TS1
#define AK09912_REG_TS2
#define AK09912_REG_TS3
#define AK09912_REG_I2CDIS
#define AK09912_REG_TS4

#define AK09912_REG_ASAX
#define AK09912_REG_ASAY
#define AK09912_REG_ASAZ

#define AK09912_MAX_REGS

/*
 * Miscellaneous values.
 */
#define AK8975_MAX_CONVERSION_TIMEOUT
#define AK8975_CONVERSION_DONE_POLL_TIME
#define AK8975_DATA_READY_TIMEOUT

/*
 * Precalculate scale factor (in Gauss units) for each axis and
 * store in the device data.
 *
 * This scale factor is axis-dependent, and is derived from 3 calibration
 * factors ASA(x), ASA(y), and ASA(z).
 *
 * These ASA values are read from the sensor device at start of day, and
 * cached in the device context struct.
 *
 * Adjusting the flux value with the sensitivity adjustment value should be
 * done via the following formula:
 *
 * Hadj = H * ( ( ( (ASA-128)*0.5 ) / 128 ) + 1 )
 * where H is the raw value, ASA is the sensitivity adjustment, and Hadj
 * is the resultant adjusted value.
 *
 * We reduce the formula to:
 *
 * Hadj = H * (ASA + 128) / 256
 *
 * H is in the range of -4096 to 4095.  The magnetometer has a range of
 * +-1229uT.  To go from the raw value to uT is:
 *
 * HuT = H * 1229/4096, or roughly, 3/10.
 *
 * Since 1uT = 0.01 gauss, our final scale factor becomes:
 *
 * Hadj = H * ((ASA + 128) / 256) * 3/10 * 1/100
 * Hadj = H * ((ASA + 128) * 0.003) / 256
 *
 * Since ASA doesn't change, we cache the resultant scale factor into the
 * device context in ak8975_setup().
 *
 * Given we use IIO_VAL_INT_PLUS_MICRO bit when displaying the scale, we
 * multiply the stored scale value by 1e6.
 */
static long ak8975_raw_to_gauss(u16 data)
{}

/*
 * For AK8963 and AK09911, same calculation, but the device is less sensitive:
 *
 * H is in the range of +-8190.  The magnetometer has a range of
 * +-4912uT.  To go from the raw value to uT is:
 *
 * HuT = H * 4912/8190, or roughly, 6/10, instead of 3/10.
 */

static long ak8963_09911_raw_to_gauss(u16 data)
{}

/*
 * For AK09912, same calculation, except the device is more sensitive:
 *
 * H is in the range of -32752 to 32752.  The magnetometer has a range of
 * +-4912uT.  To go from the raw value to uT is:
 *
 * HuT = H * 4912/32752, or roughly, 3/20, instead of 3/10.
 */
static long ak09912_raw_to_gauss(u16 data)
{}

/* Compatible Asahi Kasei Compass parts */
enum asahi_compass_chipset {};

enum ak_ctrl_reg_addr {};

enum ak_ctrl_reg_mask {};

enum ak_ctrl_mode {};

struct ak_def {};

static const struct ak_def ak_def_array[] =;

/*
 * Per-instance context data for the device.
 */
struct ak8975_data {};

/* Enable attached power regulator if any. */
static int ak8975_power_on(const struct ak8975_data *data)
{}

/* Disable attached power regulator if any. */
static void ak8975_power_off(const struct ak8975_data *data)
{}

/*
 * Return 0 if the i2c device is the one we expect.
 * return a negative error number otherwise
 */
static int ak8975_who_i_am(struct i2c_client *client,
			   enum asahi_compass_chipset type)
{}

/*
 * Helper function to write to CNTL register.
 */
static int ak8975_set_mode(struct ak8975_data *data, enum ak_ctrl_mode mode)
{}

/*
 * Handle data ready irq
 */
static irqreturn_t ak8975_irq_handler(int irq, void *data)
{}

/*
 * Install data ready interrupt handler
 */
static int ak8975_setup_irq(struct ak8975_data *data)
{}


/*
 * Perform some start-of-day setup, including reading the asa calibration
 * values and caching them.
 */
static int ak8975_setup(struct i2c_client *client)
{}

static int wait_conversion_complete_gpio(struct ak8975_data *data)
{}

static int wait_conversion_complete_polled(struct ak8975_data *data)
{}

/* Returns 0 if the end of conversion interrupt occured or -ETIME otherwise */
static int wait_conversion_complete_interrupt(struct ak8975_data *data)
{}

static int ak8975_start_read_axis(struct ak8975_data *data,
				  const struct i2c_client *client)
{}

/* Retrieve raw flux value for one of the x, y, or z axis.  */
static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
{}

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

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

static const struct iio_chan_spec_ext_info ak8975_ext_info[] =;

#define AK8975_CHANNEL(axis, index)

static const struct iio_chan_spec ak8975_channels[] =;

static const unsigned long ak8975_scan_masks[] =;

static const struct iio_info ak8975_info =;

static void ak8975_fill_buffer(struct iio_dev *indio_dev)
{}

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

static int ak8975_probe(struct i2c_client *client)
{}

static void ak8975_remove(struct i2c_client *client)
{}

static int ak8975_runtime_suspend(struct device *dev)
{}

static int ak8975_runtime_resume(struct device *dev)
{}

static DEFINE_RUNTIME_DEV_PM_OPS(ak8975_dev_pm_ops, ak8975_runtime_suspend,
				 ak8975_runtime_resume, NULL);

static const struct acpi_device_id ak_acpi_match[] =;
MODULE_DEVICE_TABLE(acpi, ak_acpi_match);

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

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

static struct i2c_driver ak8975_driver =;
module_i2c_driver();

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