![Thomas Gleixner](/assets/img/avatar_default.png)
Based on 1 normalized pattern(s): this program is free software you can redistribute it and or modify it under the terms and conditions of the gnu general public license version 2 as published by the free software foundation this program is distributed in the hope it will be useful but without any warranty without even the implied warranty of merchantability or fitness for a particular purpose see the gnu general public license for more details extracted by the scancode license scanner the SPDX license identifier GPL-2.0-only has been chosen to replace the boilerplate/reference in 263 file(s). Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Allison Randal <allison@lohutok.net> Reviewed-by: Alexios Zavras <alexios.zavras@intel.com> Cc: linux-spdx@vger.kernel.org Link: https://lkml.kernel.org/r/20190529141901.208660670@linutronix.de Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
149 lines
3.5 KiB
C
149 lines
3.5 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* IIO driver for the 3-axis accelerometer Domintech DMARD09.
|
|
*
|
|
* Copyright (c) 2016, Jelle van der Waa <jelle@vdwaa.nl>
|
|
*/
|
|
|
|
#include <asm/unaligned.h>
|
|
#include <linux/module.h>
|
|
#include <linux/i2c.h>
|
|
#include <linux/iio/iio.h>
|
|
|
|
#define DMARD09_DRV_NAME "dmard09"
|
|
|
|
#define DMARD09_REG_CHIPID 0x18
|
|
#define DMARD09_REG_STAT 0x0A
|
|
#define DMARD09_REG_X 0x0C
|
|
#define DMARD09_REG_Y 0x0E
|
|
#define DMARD09_REG_Z 0x10
|
|
#define DMARD09_CHIPID 0x95
|
|
|
|
#define DMARD09_BUF_LEN 8
|
|
#define DMARD09_AXIS_X 0
|
|
#define DMARD09_AXIS_Y 1
|
|
#define DMARD09_AXIS_Z 2
|
|
#define DMARD09_AXIS_X_OFFSET ((DMARD09_AXIS_X + 1) * 2)
|
|
#define DMARD09_AXIS_Y_OFFSET ((DMARD09_AXIS_Y + 1 )* 2)
|
|
#define DMARD09_AXIS_Z_OFFSET ((DMARD09_AXIS_Z + 1) * 2)
|
|
|
|
struct dmard09_data {
|
|
struct i2c_client *client;
|
|
};
|
|
|
|
#define DMARD09_CHANNEL(_axis, offset) { \
|
|
.type = IIO_ACCEL, \
|
|
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
|
|
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
|
|
.modified = 1, \
|
|
.address = offset, \
|
|
.channel2 = IIO_MOD_##_axis, \
|
|
}
|
|
|
|
static const struct iio_chan_spec dmard09_channels[] = {
|
|
DMARD09_CHANNEL(X, DMARD09_AXIS_X_OFFSET),
|
|
DMARD09_CHANNEL(Y, DMARD09_AXIS_Y_OFFSET),
|
|
DMARD09_CHANNEL(Z, DMARD09_AXIS_Z_OFFSET),
|
|
};
|
|
|
|
static int dmard09_read_raw(struct iio_dev *indio_dev,
|
|
struct iio_chan_spec const *chan,
|
|
int *val, int *val2, long mask)
|
|
{
|
|
struct dmard09_data *data = iio_priv(indio_dev);
|
|
u8 buf[DMARD09_BUF_LEN];
|
|
int ret;
|
|
s16 accel;
|
|
|
|
switch (mask) {
|
|
case IIO_CHAN_INFO_RAW:
|
|
/*
|
|
* Read from the DMAR09_REG_STAT register, since the chip
|
|
* caches reads from the individual X, Y, Z registers.
|
|
*/
|
|
ret = i2c_smbus_read_i2c_block_data(data->client,
|
|
DMARD09_REG_STAT,
|
|
DMARD09_BUF_LEN, buf);
|
|
if (ret < 0) {
|
|
dev_err(&data->client->dev, "Error reading reg %d\n",
|
|
DMARD09_REG_STAT);
|
|
return ret;
|
|
}
|
|
|
|
accel = get_unaligned_le16(&buf[chan->address]);
|
|
|
|
/* Remove lower 3 bits and sign extend */
|
|
accel <<= 4;
|
|
accel >>= 7;
|
|
|
|
*val = accel;
|
|
|
|
return IIO_VAL_INT;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
static const struct iio_info dmard09_info = {
|
|
.read_raw = dmard09_read_raw,
|
|
};
|
|
|
|
static int dmard09_probe(struct i2c_client *client,
|
|
const struct i2c_device_id *id)
|
|
{
|
|
int ret;
|
|
struct iio_dev *indio_dev;
|
|
struct dmard09_data *data;
|
|
|
|
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
|
|
if (!indio_dev) {
|
|
dev_err(&client->dev, "iio allocation failed\n");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
data = iio_priv(indio_dev);
|
|
data->client = client;
|
|
|
|
ret = i2c_smbus_read_byte_data(data->client, DMARD09_REG_CHIPID);
|
|
if (ret < 0) {
|
|
dev_err(&client->dev, "Error reading chip id %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
if (ret != DMARD09_CHIPID) {
|
|
dev_err(&client->dev, "Invalid chip id %d\n", ret);
|
|
return -ENODEV;
|
|
}
|
|
|
|
i2c_set_clientdata(client, indio_dev);
|
|
indio_dev->dev.parent = &client->dev;
|
|
indio_dev->name = DMARD09_DRV_NAME;
|
|
indio_dev->modes = INDIO_DIRECT_MODE;
|
|
indio_dev->channels = dmard09_channels;
|
|
indio_dev->num_channels = ARRAY_SIZE(dmard09_channels);
|
|
indio_dev->info = &dmard09_info;
|
|
|
|
return devm_iio_device_register(&client->dev, indio_dev);
|
|
}
|
|
|
|
static const struct i2c_device_id dmard09_id[] = {
|
|
{ "dmard09", 0},
|
|
{ },
|
|
};
|
|
|
|
MODULE_DEVICE_TABLE(i2c, dmard09_id);
|
|
|
|
static struct i2c_driver dmard09_driver = {
|
|
.driver = {
|
|
.name = DMARD09_DRV_NAME
|
|
},
|
|
.probe = dmard09_probe,
|
|
.id_table = dmard09_id,
|
|
};
|
|
|
|
module_i2c_driver(dmard09_driver);
|
|
|
|
MODULE_AUTHOR("Jelle van der Waa <jelle@vdwaa.nl>");
|
|
MODULE_DESCRIPTION("DMARD09 3-axis accelerometer driver");
|
|
MODULE_LICENSE("GPL");
|