linux/drivers/iio/accel/kxsd9.c

// SPDX-License-Identifier: GPL-2.0-only
/*
 * kxsd9.c	simple support for the Kionix KXSD9 3D
 *		accelerometer.
 *
 * Copyright (c) 2008-2009 Jonathan Cameron <[email protected]>
 *
 * The i2c interface is very similar, so shouldn't be a problem once
 * I have a suitable wire made up.
 *
 * TODO:	Support the motion detector
 */

#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/sysfs.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/bitops.h>
#include <linux/delay.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/triggered_buffer.h>
#include <linux/iio/trigger_consumer.h>

#include "kxsd9.h"

#define KXSD9_REG_X
#define KXSD9_REG_Y
#define KXSD9_REG_Z
#define KXSD9_REG_AUX
#define KXSD9_REG_RESET
#define KXSD9_REG_CTRL_C

#define KXSD9_CTRL_C_FS_MASK
#define KXSD9_CTRL_C_FS_8G
#define KXSD9_CTRL_C_FS_6G
#define KXSD9_CTRL_C_FS_4G
#define KXSD9_CTRL_C_FS_2G
#define KXSD9_CTRL_C_MOT_LAT
#define KXSD9_CTRL_C_MOT_LEV
#define KXSD9_CTRL_C_LP_MASK
#define KXSD9_CTRL_C_LP_NONE
#define KXSD9_CTRL_C_LP_2000HZC
#define KXSD9_CTRL_C_LP_2000HZB
#define KXSD9_CTRL_C_LP_2000HZA
#define KXSD9_CTRL_C_LP_1000HZ
#define KXSD9_CTRL_C_LP_500HZ
#define KXSD9_CTRL_C_LP_100HZ
#define KXSD9_CTRL_C_LP_50HZ

#define KXSD9_REG_CTRL_B

#define KXSD9_CTRL_B_CLK_HLD
#define KXSD9_CTRL_B_ENABLE
#define KXSD9_CTRL_B_ST

#define KXSD9_REG_CTRL_A

/**
 * struct kxsd9_state - device related storage
 * @dev: pointer to the parent device
 * @map: regmap to the device
 * @orientation: mounting matrix, flipped axis etc
 * @regs: regulators for this device, VDD and IOVDD
 * @scale: the current scaling setting
 */
struct kxsd9_state {};

#define KXSD9_SCALE_2G
#define KXSD9_SCALE_4G
#define KXSD9_SCALE_6G
#define KXSD9_SCALE_8G

/* reverse order */
static const int kxsd9_micro_scales[4] =;

#define KXSD9_ZERO_G_OFFSET

/*
 * Regulator names
 */
static const char kxsd9_reg_vdd[] =;
static const char kxsd9_reg_iovdd[] =;

static int kxsd9_write_scale(struct iio_dev *indio_dev, int micro)
{}

static IIO_CONST_ATTR(accel_scale_available,
		KXSD9_SCALE_2G " "
		KXSD9_SCALE_4G " "
		KXSD9_SCALE_6G " "
		KXSD9_SCALE_8G);

static struct attribute *kxsd9_attributes[] =;

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

static int kxsd9_read_raw(struct iio_dev *indio_dev,
			  struct iio_chan_spec const *chan,
			  int *val, int *val2, long mask)
{
	int ret = -EINVAL;
	struct kxsd9_state *st = iio_priv(indio_dev);
	unsigned int regval;
	__be16 raw_val;
	u16 nval;

	pm_runtime_get_sync(st->dev);

	switch (mask) {
	case IIO_CHAN_INFO_RAW:
		ret = regmap_bulk_read(st->map, chan->address, &raw_val,
				       sizeof(raw_val));
		if (ret)
			goto error_ret;
		nval = be16_to_cpu(raw_val);
		/* Only 12 bits are valid */
		nval >>= 4;
		*val = nval;
		ret = IIO_VAL_INT;
		break;
	case IIO_CHAN_INFO_OFFSET:
		/* This has a bias of -2048 */
		*val = KXSD9_ZERO_G_OFFSET;
		ret = IIO_VAL_INT;
		break;
	case IIO_CHAN_INFO_SCALE:
		ret = regmap_read(st->map,
				  KXSD9_REG_CTRL_C,
				  &regval);
		if (ret < 0)
			goto error_ret;
		*val = 0;
		*val2 = kxsd9_micro_scales[regval & KXSD9_CTRL_C_FS_MASK];
		ret = IIO_VAL_INT_PLUS_MICRO;
		break;
	}

error_ret:
	pm_runtime_mark_last_busy(st->dev);
	pm_runtime_put_autosuspend(st->dev);

	return ret;
};

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

static int kxsd9_buffer_preenable(struct iio_dev *indio_dev)
{}

static int kxsd9_buffer_postdisable(struct iio_dev *indio_dev)
{}

static const struct iio_buffer_setup_ops kxsd9_buffer_setup_ops =;

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

static const struct iio_chan_spec_ext_info kxsd9_ext_info[] =;

#define KXSD9_ACCEL_CHAN(axis, index)

static const struct iio_chan_spec kxsd9_channels[] =;

static const struct attribute_group kxsd9_attribute_group =;

static int kxsd9_power_up(struct kxsd9_state *st)
{
	int ret;

	/* Enable the regulators */
	ret = regulator_bulk_enable(ARRAY_SIZE(st->regs), st->regs);
	if (ret) {
		dev_err(st->dev, "Cannot enable regulators\n");
		return ret;
	}

	/* Power up */
	ret = regmap_write(st->map,
			   KXSD9_REG_CTRL_B,
			   KXSD9_CTRL_B_ENABLE);
	if (ret)
		return ret;

	/*
	 * Set 1000Hz LPF, 2g fullscale, motion wakeup threshold 1g,
	 * latched wakeup
	 */
	ret = regmap_write(st->map,
			   KXSD9_REG_CTRL_C,
			   KXSD9_CTRL_C_LP_1000HZ |
			   KXSD9_CTRL_C_MOT_LEV	|
			   KXSD9_CTRL_C_MOT_LAT |
			   st->scale);
	if (ret)
		return ret;

	/*
	 * Power-up time depends on the LPF setting, but typ 15.9 ms, let's
	 * set 20 ms to allow for some slack.
	 */
	msleep(20);

	return 0;
};

static int kxsd9_power_down(struct kxsd9_state *st)
{}

static const struct iio_info kxsd9_info =;

/* Four channels apart from timestamp, scan mask = 0x0f */
static const unsigned long kxsd9_scan_masks[] =;

int kxsd9_common_probe(struct device *dev,
		       struct regmap *map,
		       const char *name)
{}
EXPORT_SYMBOL_NS();

void kxsd9_common_remove(struct device *dev)
{}
EXPORT_SYMBOL_NS();

static int kxsd9_runtime_suspend(struct device *dev)
{}

static int kxsd9_runtime_resume(struct device *dev)
{}

EXPORT_NS_RUNTIME_DEV_PM_OPS(kxsd9_dev_pm_ops, kxsd9_runtime_suspend,
			     kxsd9_runtime_resume, NULL, IIO_KXSD9);

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