brintos

brintos / linux-shallow public Read only

0
0
Text · 12.8 KiB · 495b64a Raw
434 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * ADIS16260/ADIS16265 Programmable Digital Gyroscope Sensor Driver4 *5 * Copyright 2010 Analog Devices Inc.6 */7 8#include <linux/device.h>9#include <linux/kernel.h>10#include <linux/spi/spi.h>11#include <linux/module.h>12 13#include <linux/iio/iio.h>14#include <linux/iio/imu/adis.h>15 16#define ADIS16260_STARTUP_DELAY	220 /* ms */17 18#define ADIS16260_FLASH_CNT  0x00 /* Flash memory write count */19#define ADIS16260_SUPPLY_OUT 0x02 /* Power supply measurement */20#define ADIS16260_GYRO_OUT   0x04 /* X-axis gyroscope output */21#define ADIS16260_AUX_ADC    0x0A /* analog input channel measurement */22#define ADIS16260_TEMP_OUT   0x0C /* internal temperature measurement */23#define ADIS16260_ANGL_OUT   0x0E /* angle displacement */24#define ADIS16260_GYRO_OFF   0x14 /* Calibration, offset/bias adjustment */25#define ADIS16260_GYRO_SCALE 0x16 /* Calibration, scale adjustment */26#define ADIS16260_ALM_MAG1   0x20 /* Alarm 1 magnitude/polarity setting */27#define ADIS16260_ALM_MAG2   0x22 /* Alarm 2 magnitude/polarity setting */28#define ADIS16260_ALM_SMPL1  0x24 /* Alarm 1 dynamic rate of change setting */29#define ADIS16260_ALM_SMPL2  0x26 /* Alarm 2 dynamic rate of change setting */30#define ADIS16260_ALM_CTRL   0x28 /* Alarm control */31#define ADIS16260_AUX_DAC    0x30 /* Auxiliary DAC data */32#define ADIS16260_GPIO_CTRL  0x32 /* Control, digital I/O line */33#define ADIS16260_MSC_CTRL   0x34 /* Control, data ready, self-test settings */34#define ADIS16260_SMPL_PRD   0x36 /* Control, internal sample rate */35#define ADIS16260_SENS_AVG   0x38 /* Control, dynamic range, filtering */36#define ADIS16260_SLP_CNT    0x3A /* Control, sleep mode initiation */37#define ADIS16260_DIAG_STAT  0x3C /* Diagnostic, error flags */38#define ADIS16260_GLOB_CMD   0x3E /* Control, global commands */39#define ADIS16260_LOT_ID1    0x52 /* Lot Identification Code 1 */40#define ADIS16260_LOT_ID2    0x54 /* Lot Identification Code 2 */41#define ADIS16260_PROD_ID    0x56 /* Product identifier;42				   * convert to decimal = 16,265/16,260 */43#define ADIS16260_SERIAL_NUM 0x58 /* Serial number */44 45#define ADIS16260_ERROR_ACTIVE			(1<<14)46#define ADIS16260_NEW_DATA			(1<<15)47 48/* MSC_CTRL */49#define ADIS16260_MSC_CTRL_MEM_TEST		(1<<11)50/* Internal self-test enable */51#define ADIS16260_MSC_CTRL_INT_SELF_TEST	(1<<10)52#define ADIS16260_MSC_CTRL_NEG_SELF_TEST	(1<<9)53#define ADIS16260_MSC_CTRL_POS_SELF_TEST	(1<<8)54#define ADIS16260_MSC_CTRL_DATA_RDY_EN		(1<<2)55#define ADIS16260_MSC_CTRL_DATA_RDY_POL_HIGH	(1<<1)56#define ADIS16260_MSC_CTRL_DATA_RDY_DIO2	(1<<0)57 58/* SMPL_PRD */59/* Time base (tB): 0 = 1.953 ms, 1 = 60.54 ms */60#define ADIS16260_SMPL_PRD_TIME_BASE	(1<<7)61#define ADIS16260_SMPL_PRD_DIV_MASK	0x7F62 63/* SLP_CNT */64#define ADIS16260_SLP_CNT_POWER_OFF     0x8065 66/* DIAG_STAT */67#define ADIS16260_DIAG_STAT_ALARM2	(1<<9)68#define ADIS16260_DIAG_STAT_ALARM1	(1<<8)69#define ADIS16260_DIAG_STAT_FLASH_CHK_BIT	670#define ADIS16260_DIAG_STAT_SELF_TEST_BIT	571#define ADIS16260_DIAG_STAT_OVERFLOW_BIT	472#define ADIS16260_DIAG_STAT_SPI_FAIL_BIT	373#define ADIS16260_DIAG_STAT_FLASH_UPT_BIT	274#define ADIS16260_DIAG_STAT_POWER_HIGH_BIT	175#define ADIS16260_DIAG_STAT_POWER_LOW_BIT	076 77/* GLOB_CMD */78#define ADIS16260_GLOB_CMD_SW_RESET	(1<<7)79#define ADIS16260_GLOB_CMD_FLASH_UPD	(1<<3)80#define ADIS16260_GLOB_CMD_DAC_LATCH	(1<<2)81#define ADIS16260_GLOB_CMD_FAC_CALIB	(1<<1)82#define ADIS16260_GLOB_CMD_AUTO_NULL	(1<<0)83 84#define ADIS16260_SPI_SLOW	(u32)(300 * 1000)85#define ADIS16260_SPI_BURST	(u32)(1000 * 1000)86#define ADIS16260_SPI_FAST	(u32)(2000 * 1000)87 88/* At the moment triggers are only used for ring buffer89 * filling. This may change!90 */91 92#define ADIS16260_SCAN_GYRO	093#define ADIS16260_SCAN_SUPPLY	194#define ADIS16260_SCAN_AUX_ADC	295#define ADIS16260_SCAN_TEMP	396#define ADIS16260_SCAN_ANGL	497 98struct adis16260_chip_info {99	unsigned int gyro_max_val;100	unsigned int gyro_max_scale;101	const struct iio_chan_spec *channels;102	unsigned int num_channels;103};104 105struct adis16260 {106	const struct adis16260_chip_info *info;107 108	struct adis adis;109};110 111enum adis16260_type {112	ADIS16251,113	ADIS16260,114	ADIS16266,115};116 117static const struct iio_chan_spec adis16260_channels[] = {118	ADIS_GYRO_CHAN(X, ADIS16260_GYRO_OUT, ADIS16260_SCAN_GYRO,119		BIT(IIO_CHAN_INFO_CALIBBIAS) |120		BIT(IIO_CHAN_INFO_CALIBSCALE),121		BIT(IIO_CHAN_INFO_SAMP_FREQ), 14),122	ADIS_INCLI_CHAN(X, ADIS16260_ANGL_OUT, ADIS16260_SCAN_ANGL, 0,123		BIT(IIO_CHAN_INFO_SAMP_FREQ), 14),124	ADIS_TEMP_CHAN(ADIS16260_TEMP_OUT, ADIS16260_SCAN_TEMP,125		BIT(IIO_CHAN_INFO_SAMP_FREQ), 12),126	ADIS_SUPPLY_CHAN(ADIS16260_SUPPLY_OUT, ADIS16260_SCAN_SUPPLY,127		BIT(IIO_CHAN_INFO_SAMP_FREQ), 12),128	ADIS_AUX_ADC_CHAN(ADIS16260_AUX_ADC, ADIS16260_SCAN_AUX_ADC,129		BIT(IIO_CHAN_INFO_SAMP_FREQ), 12),130	IIO_CHAN_SOFT_TIMESTAMP(5),131};132 133static const struct iio_chan_spec adis16266_channels[] = {134	ADIS_GYRO_CHAN(X, ADIS16260_GYRO_OUT, ADIS16260_SCAN_GYRO,135		BIT(IIO_CHAN_INFO_CALIBBIAS) |136		BIT(IIO_CHAN_INFO_CALIBSCALE),137		BIT(IIO_CHAN_INFO_SAMP_FREQ), 14),138	ADIS_TEMP_CHAN(ADIS16260_TEMP_OUT, ADIS16260_SCAN_TEMP,139		BIT(IIO_CHAN_INFO_SAMP_FREQ), 12),140	ADIS_SUPPLY_CHAN(ADIS16260_SUPPLY_OUT, ADIS16260_SCAN_SUPPLY,141		BIT(IIO_CHAN_INFO_SAMP_FREQ), 12),142	ADIS_AUX_ADC_CHAN(ADIS16260_AUX_ADC, ADIS16260_SCAN_AUX_ADC,143		BIT(IIO_CHAN_INFO_SAMP_FREQ), 12),144	IIO_CHAN_SOFT_TIMESTAMP(4),145};146 147static const struct adis16260_chip_info adis16260_chip_info_table[] = {148	[ADIS16251] = {149		.gyro_max_scale = 80,150		.gyro_max_val = IIO_RAD_TO_DEGREE(4368),151		.channels = adis16260_channels,152		.num_channels = ARRAY_SIZE(adis16260_channels),153	},154	[ADIS16260] = {155		.gyro_max_scale = 320,156		.gyro_max_val = IIO_RAD_TO_DEGREE(4368),157		.channels = adis16260_channels,158		.num_channels = ARRAY_SIZE(adis16260_channels),159	},160	[ADIS16266] = {161		.gyro_max_scale = 14000,162		.gyro_max_val = IIO_RAD_TO_DEGREE(3357),163		.channels = adis16266_channels,164		.num_channels = ARRAY_SIZE(adis16266_channels),165	},166};167 168/* Power down the device */169static int adis16260_stop_device(struct iio_dev *indio_dev)170{171	struct adis16260 *adis16260 = iio_priv(indio_dev);172	int ret;173	u16 val = ADIS16260_SLP_CNT_POWER_OFF;174 175	ret = adis_write_reg_16(&adis16260->adis, ADIS16260_SLP_CNT, val);176	if (ret)177		dev_err(&indio_dev->dev, "problem with turning device off: SLP_CNT");178 179	return ret;180}181 182static const u8 adis16260_addresses[][2] = {183	[ADIS16260_SCAN_GYRO] = { ADIS16260_GYRO_OFF, ADIS16260_GYRO_SCALE },184};185 186static int adis16260_read_raw(struct iio_dev *indio_dev,187			      struct iio_chan_spec const *chan,188			      int *val, int *val2,189			      long mask)190{191	struct adis16260 *adis16260 = iio_priv(indio_dev);192	const struct adis16260_chip_info *info = adis16260->info;193	struct adis *adis = &adis16260->adis;194	int ret;195	u8 addr;196	s16 val16;197 198	switch (mask) {199	case IIO_CHAN_INFO_RAW:200		return adis_single_conversion(indio_dev, chan,201				ADIS16260_ERROR_ACTIVE, val);202	case IIO_CHAN_INFO_SCALE:203		switch (chan->type) {204		case IIO_ANGL_VEL:205			*val = info->gyro_max_scale;206			*val2 = info->gyro_max_val;207			return IIO_VAL_FRACTIONAL;208		case IIO_INCLI:209			*val = 0;210			*val2 = IIO_DEGREE_TO_RAD(36630);211			return IIO_VAL_INT_PLUS_MICRO;212		case IIO_VOLTAGE:213			if (chan->channel == 0) {214				*val = 1;215				*val2 = 831500; /* 1.8315 mV */216			} else {217				*val = 0;218				*val2 = 610500; /* 610.5 uV */219			}220			return IIO_VAL_INT_PLUS_MICRO;221		case IIO_TEMP:222			*val = 145;223			*val2 = 300000; /* 0.1453 C */224			return IIO_VAL_INT_PLUS_MICRO;225		default:226			return -EINVAL;227		}228	case IIO_CHAN_INFO_OFFSET:229		*val = 250000 / 1453; /* 25 C = 0x00 */230		return IIO_VAL_INT;231	case IIO_CHAN_INFO_CALIBBIAS:232		addr = adis16260_addresses[chan->scan_index][0];233		ret = adis_read_reg_16(adis, addr, &val16);234		if (ret)235			return ret;236 237		*val = sign_extend32(val16, 11);238		return IIO_VAL_INT;239	case IIO_CHAN_INFO_CALIBSCALE:240		addr = adis16260_addresses[chan->scan_index][1];241		ret = adis_read_reg_16(adis, addr, &val16);242		if (ret)243			return ret;244 245		*val = val16;246		return IIO_VAL_INT;247	case IIO_CHAN_INFO_SAMP_FREQ:248		ret = adis_read_reg_16(adis, ADIS16260_SMPL_PRD, &val16);249		if (ret)250			return ret;251 252		if (spi_get_device_id(adis->spi)->driver_data)253		/* If an adis16251 */254			*val = (val16 & ADIS16260_SMPL_PRD_TIME_BASE) ?255				8 : 256;256		else257			*val = (val16 & ADIS16260_SMPL_PRD_TIME_BASE) ?258				66 : 2048;259		*val /= (val16 & ADIS16260_SMPL_PRD_DIV_MASK) + 1;260		return IIO_VAL_INT;261	}262	return -EINVAL;263}264 265static int adis16260_write_raw(struct iio_dev *indio_dev,266			       struct iio_chan_spec const *chan,267			       int val,268			       int val2,269			       long mask)270{271	struct adis16260 *adis16260 = iio_priv(indio_dev);272	struct adis *adis = &adis16260->adis;273	u8 addr;274	u8 t;275 276	switch (mask) {277	case IIO_CHAN_INFO_CALIBBIAS:278		if (val < -2048 || val >= 2048)279			return -EINVAL;280 281		addr = adis16260_addresses[chan->scan_index][0];282		return adis_write_reg_16(adis, addr, val);283	case IIO_CHAN_INFO_CALIBSCALE:284		if (val < 0 || val >= 4096)285			return -EINVAL;286 287		addr = adis16260_addresses[chan->scan_index][1];288		return adis_write_reg_16(adis, addr, val);289	case IIO_CHAN_INFO_SAMP_FREQ:290		if (spi_get_device_id(adis->spi)->driver_data)291			t = 256 / val;292		else293			t = 2048 / val;294 295		if (t > ADIS16260_SMPL_PRD_DIV_MASK)296			t = ADIS16260_SMPL_PRD_DIV_MASK;297		else if (t > 0)298			t--;299		adis_dev_auto_scoped_lock(adis) {300			if (t >= 0x0A)301				adis->spi->max_speed_hz = ADIS16260_SPI_SLOW;302			else303				adis->spi->max_speed_hz = ADIS16260_SPI_FAST;304			return __adis_write_reg_8(adis, ADIS16260_SMPL_PRD, t);305		}306		unreachable();307	}308	return -EINVAL;309}310 311static const struct iio_info adis16260_info = {312	.read_raw = &adis16260_read_raw,313	.write_raw = &adis16260_write_raw,314	.update_scan_mode = adis_update_scan_mode,315};316 317static const char * const adis1620_status_error_msgs[] = {318	[ADIS16260_DIAG_STAT_FLASH_CHK_BIT] = "Flash checksum error",319	[ADIS16260_DIAG_STAT_SELF_TEST_BIT] = "Self test error",320	[ADIS16260_DIAG_STAT_OVERFLOW_BIT] = "Sensor overrange",321	[ADIS16260_DIAG_STAT_SPI_FAIL_BIT] = "SPI failure",322	[ADIS16260_DIAG_STAT_FLASH_UPT_BIT] = "Flash update failed",323	[ADIS16260_DIAG_STAT_POWER_HIGH_BIT] = "Power supply above 5.25",324	[ADIS16260_DIAG_STAT_POWER_LOW_BIT] = "Power supply below 4.75",325};326 327static const struct adis_timeout adis16260_timeouts = {328	.reset_ms = ADIS16260_STARTUP_DELAY,329	.sw_reset_ms = ADIS16260_STARTUP_DELAY,330	.self_test_ms = ADIS16260_STARTUP_DELAY,331};332 333static const struct adis_data adis16260_data = {334	.write_delay = 30,335	.read_delay = 30,336	.msc_ctrl_reg = ADIS16260_MSC_CTRL,337	.glob_cmd_reg = ADIS16260_GLOB_CMD,338	.diag_stat_reg = ADIS16260_DIAG_STAT,339 340	.self_test_mask = ADIS16260_MSC_CTRL_MEM_TEST,341	.self_test_reg = ADIS16260_MSC_CTRL,342	.timeouts = &adis16260_timeouts,343 344	.status_error_msgs = adis1620_status_error_msgs,345	.status_error_mask = BIT(ADIS16260_DIAG_STAT_FLASH_CHK_BIT) |346		BIT(ADIS16260_DIAG_STAT_SELF_TEST_BIT) |347		BIT(ADIS16260_DIAG_STAT_OVERFLOW_BIT) |348		BIT(ADIS16260_DIAG_STAT_SPI_FAIL_BIT) |349		BIT(ADIS16260_DIAG_STAT_FLASH_UPT_BIT) |350		BIT(ADIS16260_DIAG_STAT_POWER_HIGH_BIT) |351		BIT(ADIS16260_DIAG_STAT_POWER_LOW_BIT),352};353 354static void adis16260_stop(void *data)355{356	adis16260_stop_device(data);357}358 359static int adis16260_probe(struct spi_device *spi)360{361	const struct spi_device_id *id;362	struct adis16260 *adis16260;363	struct iio_dev *indio_dev;364	int ret;365 366	id = spi_get_device_id(spi);367	if (!id)368		return -ENODEV;369 370	/* setup the industrialio driver allocated elements */371	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adis16260));372	if (!indio_dev)373		return -ENOMEM;374	adis16260 = iio_priv(indio_dev);375	/* this is only used for removal purposes */376	spi_set_drvdata(spi, indio_dev);377 378	adis16260->info = &adis16260_chip_info_table[id->driver_data];379 380	indio_dev->name = id->name;381	indio_dev->info = &adis16260_info;382	indio_dev->channels = adis16260->info->channels;383	indio_dev->num_channels = adis16260->info->num_channels;384	indio_dev->modes = INDIO_DIRECT_MODE;385 386	ret = adis_init(&adis16260->adis, indio_dev, spi, &adis16260_data);387	if (ret)388		return ret;389 390	ret = devm_adis_setup_buffer_and_trigger(&adis16260->adis, indio_dev, NULL);391	if (ret)392		return ret;393 394	/* Get the device into a sane initial state */395	ret = __adis_initial_startup(&adis16260->adis);396	if (ret)397		return ret;398 399	ret = devm_add_action_or_reset(&spi->dev, adis16260_stop, indio_dev);400	if (ret)401		return ret;402 403	return devm_iio_device_register(&spi->dev, indio_dev);404}405 406/*407 * These parts do not need to be differentiated until someone adds408 * support for the on chip filtering.409 */410static const struct spi_device_id adis16260_id[] = {411	{"adis16260", ADIS16260},412	{"adis16265", ADIS16260},413	{"adis16266", ADIS16266},414	{"adis16250", ADIS16260},415	{"adis16255", ADIS16260},416	{"adis16251", ADIS16251},417	{}418};419MODULE_DEVICE_TABLE(spi, adis16260_id);420 421static struct spi_driver adis16260_driver = {422	.driver = {423		.name = "adis16260",424	},425	.probe = adis16260_probe,426	.id_table = adis16260_id,427};428module_spi_driver(adis16260_driver);429 430MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");431MODULE_DESCRIPTION("Analog Devices ADIS16260/5 Digital Gyroscope Sensor");432MODULE_LICENSE("GPL v2");433MODULE_IMPORT_NS(IIO_ADISLIB);434