/*
* adis16400.c support Analog Devices ADIS16400/5
* 3d 2g Linear Accelerometers,
* 3d Gyroscopes,
* 3d Magnetometers via SPI
*
* Copyright (c) 2009 Manuel Stahl <manuel.stahl@iis.fraunhofer.de>
* Copyright (c) 2007 Jonathan Cameron <jic23@kernel.org>
* Copyright (c) 2011 Analog Devices Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/debugfs.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
#include "adis16400.h"
#ifdef CONFIG_DEBUG_FS
static ssize_t adis16400_show_serial_number(struct file *file,
char __user *userbuf, size_t count, loff_t *ppos)
{
struct adis16400_state *st = file->private_data;
u16 lot1, lot2, serial_number;
char buf[16];
size_t len;
int ret;
ret = adis_read_reg_16(&st->adis, ADIS16334_LOT_ID1, &lot1);
if (ret < 0)
return ret;
ret = adis_read_reg_16(&st->adis, ADIS16334_LOT_ID2, &lot2);
if (ret < 0)
return ret;
ret = adis_read_reg_16(&st->adis, ADIS16334_SERIAL_NUMBER,
&serial_number);
if (ret < 0)
return ret;
len = snprintf(buf, sizeof(buf), "%.4x-%.4x-%.4x\n", lot1, lot2,
serial_number);
return simple_read_from_buffer(userbuf, count, ppos, buf, len);
}
static const struct file_operations adis16400_serial_number_fops = {
.open = simple_open,
.read = adis16400_show_serial_number,
.llseek = default_llseek,
.owner = THIS_MODULE,
};
static int adis16400_show_product_id(void *arg, u64 *val)
{
struct adis16400_state *st = arg;
uint16_t prod_id;
int ret;
ret = adis_read_reg_16(&st->adis, ADIS16400_PRODUCT_ID, &prod_id);
if (ret < 0)
return ret;
*val = prod_id;
return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(adis16400_product_id_fops,
adis16400_show_product_id, NULL, "%lld\n");
static int adis16400_show_flash_count(void *arg, u64 *val)
{
struct adis16400_state *st = arg;
uint16_t flash_count;
int ret;
ret = adis_read_reg_16(&st->adis, ADIS16400_FLASH_CNT, &flash_count);
if (ret < 0)
return ret;
*val = flash_count;
return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(adis16400_flash_count_fops,
adis16400_show_flash_count, NULL, "%lld\n");
static int adis16400_debugfs_init(struct iio_dev *indio_dev)
{
struct adis16400_state *st = iio_priv(indio_dev);
if (st->variant->flags & ADIS16400_HAS_SERIAL_NUMBER)
debugfs_create_file("serial_number", 0400,
indio_dev->debugfs_dentry, st,
&adis16400_serial_number_fops);
if (st->variant->flags & ADIS16400_HAS_PROD_ID)
debugfs_create_file("product_id", 0400,
indio_dev->debugfs_dentry, st,
&adis16400_product_id_fops);
debugfs_create_file("flash_count", 0400, indio_dev->debugfs_dentry,
st, &adis16400_flash_count_fops);
return 0;
}
#else
static int adis16400_debugfs_init(struct iio_dev *indio_dev)
{
return 0;
}
#endif
enum adis16400_chip_variant {
ADIS16300,
ADIS16334,
ADIS16350,
ADIS16360,
ADIS16362,
ADIS16364,
ADIS16400,
ADIS16448,
};
static int adis16334_get_freq(struct adis16400_state *st)
{
int ret;
uint16_t t;
ret = adis_read_reg_16(&st->adis, ADIS16400_SMPL_PRD, &t);
if (ret < 0)
return ret;
t >>= ADIS16334_RATE_DIV_SHIFT;
return 819200 >> t;
}
static int adis16334_set_freq(struct adis16400_state *st, unsigned int freq)
{
unsigned int t;
if (freq < 819200)
t = ilog2(819200 / freq);
else
t = 0;
if (t > 0x31)
t = 0x31;
t