brintos

brintos / linux-shallow public Read only

0
0
Text · 12.8 KiB · 9941073 Raw
537 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Common library for ADIS16XXX devices4 *5 * Copyright 2012 Analog Devices Inc.6 *   Author: Lars-Peter Clausen <lars@metafoo.de>7 */8 9#include <linux/delay.h>10#include <linux/gpio/consumer.h>11#include <linux/mutex.h>12#include <linux/device.h>13#include <linux/kernel.h>14#include <linux/spi/spi.h>15#include <linux/module.h>16#include <linux/unaligned.h>17 18#include <linux/iio/iio.h>19#include <linux/iio/imu/adis.h>20 21#define ADIS_MSC_CTRL_DATA_RDY_EN	BIT(2)22#define ADIS_MSC_CTRL_DATA_RDY_POL_HIGH	BIT(1)23#define ADIS_MSC_CTRL_DATA_RDY_DIO2	BIT(0)24#define ADIS_GLOB_CMD_SW_RESET		BIT(7)25 26/**27 * __adis_write_reg() - write N bytes to register (unlocked version)28 * @adis: The adis device29 * @reg: The address of the lower of the two registers30 * @value: The value to write to device (up to 4 bytes)31 * @size: The size of the @value (in bytes)32 */33int __adis_write_reg(struct adis *adis, unsigned int reg, unsigned int value,34		     unsigned int size)35{36	unsigned int page = reg / ADIS_PAGE_SIZE;37	int ret, i;38	struct spi_message msg;39	struct spi_transfer xfers[] = {40		{41			.tx_buf = adis->tx,42			.bits_per_word = 8,43			.len = 2,44			.cs_change = 1,45			.delay.value = adis->data->write_delay,46			.delay.unit = SPI_DELAY_UNIT_USECS,47		}, {48			.tx_buf = adis->tx + 2,49			.bits_per_word = 8,50			.len = 2,51			.cs_change = 1,52			.delay.value = adis->data->write_delay,53			.delay.unit = SPI_DELAY_UNIT_USECS,54		}, {55			.tx_buf = adis->tx + 4,56			.bits_per_word = 8,57			.len = 2,58			.cs_change = 1,59			.delay.value = adis->data->write_delay,60			.delay.unit = SPI_DELAY_UNIT_USECS,61		}, {62			.tx_buf = adis->tx + 6,63			.bits_per_word = 8,64			.len = 2,65			.delay.value = adis->data->write_delay,66			.delay.unit = SPI_DELAY_UNIT_USECS,67		}, {68			.tx_buf = adis->tx + 8,69			.bits_per_word = 8,70			.len = 2,71			.delay.value = adis->data->write_delay,72			.delay.unit = SPI_DELAY_UNIT_USECS,73		},74	};75 76	spi_message_init(&msg);77 78	if (adis->current_page != page) {79		adis->tx[0] = ADIS_WRITE_REG(ADIS_REG_PAGE_ID);80		adis->tx[1] = page;81		spi_message_add_tail(&xfers[0], &msg);82	}83 84	switch (size) {85	case 4:86		adis->tx[8] = ADIS_WRITE_REG(reg + 3);87		adis->tx[9] = (value >> 24) & 0xff;88		adis->tx[6] = ADIS_WRITE_REG(reg + 2);89		adis->tx[7] = (value >> 16) & 0xff;90		fallthrough;91	case 2:92		adis->tx[4] = ADIS_WRITE_REG(reg + 1);93		adis->tx[5] = (value >> 8) & 0xff;94		fallthrough;95	case 1:96		adis->tx[2] = ADIS_WRITE_REG(reg);97		adis->tx[3] = value & 0xff;98		break;99	default:100		return -EINVAL;101	}102 103	xfers[size].cs_change = 0;104 105	for (i = 1; i <= size; i++)106		spi_message_add_tail(&xfers[i], &msg);107 108	ret = spi_sync(adis->spi, &msg);109	if (ret) {110		dev_err(&adis->spi->dev, "Failed to write register 0x%02X: %d\n",111			reg, ret);112	} else {113		adis->current_page = page;114	}115 116	return ret;117}118EXPORT_SYMBOL_NS_GPL(__adis_write_reg, IIO_ADISLIB);119 120/**121 * __adis_read_reg() - read N bytes from register (unlocked version)122 * @adis: The adis device123 * @reg: The address of the lower of the two registers124 * @val: The value read back from the device125 * @size: The size of the @val buffer126 */127int __adis_read_reg(struct adis *adis, unsigned int reg, unsigned int *val,128		    unsigned int size)129{130	unsigned int page = reg / ADIS_PAGE_SIZE;131	struct spi_message msg;132	int ret;133	struct spi_transfer xfers[] = {134		{135			.tx_buf = adis->tx,136			.bits_per_word = 8,137			.len = 2,138			.cs_change = 1,139			.delay.value = adis->data->write_delay,140			.delay.unit = SPI_DELAY_UNIT_USECS,141		}, {142			.tx_buf = adis->tx + 2,143			.bits_per_word = 8,144			.len = 2,145			.cs_change = 1,146			.delay.value = adis->data->read_delay,147			.delay.unit = SPI_DELAY_UNIT_USECS,148		}, {149			.tx_buf = adis->tx + 4,150			.rx_buf = adis->rx,151			.bits_per_word = 8,152			.len = 2,153			.cs_change = 1,154			.delay.value = adis->data->read_delay,155			.delay.unit = SPI_DELAY_UNIT_USECS,156		}, {157			.rx_buf = adis->rx + 2,158			.bits_per_word = 8,159			.len = 2,160			.delay.value = adis->data->read_delay,161			.delay.unit = SPI_DELAY_UNIT_USECS,162		},163	};164 165	spi_message_init(&msg);166 167	if (adis->current_page != page) {168		adis->tx[0] = ADIS_WRITE_REG(ADIS_REG_PAGE_ID);169		adis->tx[1] = page;170		spi_message_add_tail(&xfers[0], &msg);171	}172 173	switch (size) {174	case 4:175		adis->tx[2] = ADIS_READ_REG(reg + 2);176		adis->tx[3] = 0;177		spi_message_add_tail(&xfers[1], &msg);178		fallthrough;179	case 2:180		adis->tx[4] = ADIS_READ_REG(reg);181		adis->tx[5] = 0;182		spi_message_add_tail(&xfers[2], &msg);183		spi_message_add_tail(&xfers[3], &msg);184		break;185	default:186		return -EINVAL;187	}188 189	ret = spi_sync(adis->spi, &msg);190	if (ret) {191		dev_err(&adis->spi->dev, "Failed to read register 0x%02X: %d\n",192			reg, ret);193		return ret;194	}195 196	adis->current_page = page;197 198	switch (size) {199	case 4:200		*val = get_unaligned_be32(adis->rx);201		break;202	case 2:203		*val = get_unaligned_be16(adis->rx + 2);204		break;205	}206 207	return ret;208}209EXPORT_SYMBOL_NS_GPL(__adis_read_reg, IIO_ADISLIB);210/**211 * __adis_update_bits_base() - ADIS Update bits function - Unlocked version212 * @adis: The adis device213 * @reg: The address of the lower of the two registers214 * @mask: Bitmask to change215 * @val: Value to be written216 * @size: Size of the register to update217 *218 * Updates the desired bits of @reg in accordance with @mask and @val.219 */220int __adis_update_bits_base(struct adis *adis, unsigned int reg, const u32 mask,221			    const u32 val, u8 size)222{223	int ret;224	u32 __val;225 226	ret = __adis_read_reg(adis, reg, &__val, size);227	if (ret)228		return ret;229 230	__val = (__val & ~mask) | (val & mask);231 232	return __adis_write_reg(adis, reg, __val, size);233}234EXPORT_SYMBOL_NS_GPL(__adis_update_bits_base, IIO_ADISLIB);235 236#ifdef CONFIG_DEBUG_FS237 238int adis_debugfs_reg_access(struct iio_dev *indio_dev, unsigned int reg,239			    unsigned int writeval, unsigned int *readval)240{241	struct adis *adis = iio_device_get_drvdata(indio_dev);242 243	if (readval) {244		u16 val16;245		int ret;246 247		ret = adis_read_reg_16(adis, reg, &val16);248		if (ret == 0)249			*readval = val16;250 251		return ret;252	}253 254	return adis_write_reg_16(adis, reg, writeval);255}256EXPORT_SYMBOL_NS(adis_debugfs_reg_access, IIO_ADISLIB);257 258#endif259 260/**261 * __adis_enable_irq() - Enable or disable data ready IRQ (unlocked)262 * @adis: The adis device263 * @enable: Whether to enable the IRQ264 *265 * Returns 0 on success, negative error code otherwise266 */267int __adis_enable_irq(struct adis *adis, bool enable)268{269	int ret;270	u16 msc;271 272	if (adis->data->enable_irq)273		return adis->data->enable_irq(adis, enable);274 275	if (adis->data->unmasked_drdy) {276		if (enable)277			enable_irq(adis->spi->irq);278		else279			disable_irq(adis->spi->irq);280 281		return 0;282	}283 284	ret = __adis_read_reg_16(adis, adis->data->msc_ctrl_reg, &msc);285	if (ret)286		return ret;287 288	msc |= ADIS_MSC_CTRL_DATA_RDY_POL_HIGH;289	msc &= ~ADIS_MSC_CTRL_DATA_RDY_DIO2;290	if (enable)291		msc |= ADIS_MSC_CTRL_DATA_RDY_EN;292	else293		msc &= ~ADIS_MSC_CTRL_DATA_RDY_EN;294 295	return __adis_write_reg_16(adis, adis->data->msc_ctrl_reg, msc);296}297EXPORT_SYMBOL_NS(__adis_enable_irq, IIO_ADISLIB);298 299/**300 * __adis_check_status() - Check the device for error conditions (unlocked)301 * @adis: The adis device302 *303 * Returns 0 on success, a negative error code otherwise304 */305int __adis_check_status(struct adis *adis)306{307	u16 status;308	int ret;309	int i;310 311	ret = __adis_read_reg_16(adis, adis->data->diag_stat_reg, &status);312	if (ret)313		return ret;314 315	status &= adis->data->status_error_mask;316 317	if (status == 0)318		return 0;319 320	for (i = 0; i < 16; ++i) {321		if (status & BIT(i)) {322			dev_err(&adis->spi->dev, "%s.\n",323				adis->data->status_error_msgs[i]);324		}325	}326 327	return -EIO;328}329EXPORT_SYMBOL_NS_GPL(__adis_check_status, IIO_ADISLIB);330 331/**332 * __adis_reset() - Reset the device (unlocked version)333 * @adis: The adis device334 *335 * Returns 0 on success, a negative error code otherwise336 */337int __adis_reset(struct adis *adis)338{339	int ret;340	const struct adis_timeout *timeouts = adis->data->timeouts;341 342	ret = __adis_write_reg_8(adis, adis->data->glob_cmd_reg,343				 ADIS_GLOB_CMD_SW_RESET);344	if (ret) {345		dev_err(&adis->spi->dev, "Failed to reset device: %d\n", ret);346		return ret;347	}348 349	msleep(timeouts->sw_reset_ms);350 351	return 0;352}353EXPORT_SYMBOL_NS_GPL(__adis_reset, IIO_ADIS_LIB);354 355static int adis_self_test(struct adis *adis)356{357	int ret;358	const struct adis_timeout *timeouts = adis->data->timeouts;359 360	ret = __adis_write_reg_16(adis, adis->data->self_test_reg,361				  adis->data->self_test_mask);362	if (ret) {363		dev_err(&adis->spi->dev, "Failed to initiate self test: %d\n",364			ret);365		return ret;366	}367 368	msleep(timeouts->self_test_ms);369 370	ret = __adis_check_status(adis);371 372	if (adis->data->self_test_no_autoclear)373		__adis_write_reg_16(adis, adis->data->self_test_reg, 0x00);374 375	return ret;376}377 378/**379 * __adis_initial_startup() - Device initial setup380 * @adis: The adis device381 *382 * The function performs a HW reset via a reset pin that should be specified383 * via GPIOLIB. If no pin is configured a SW reset will be performed.384 * The RST pin for the ADIS devices should be configured as ACTIVE_LOW.385 *386 * After the self-test operation is performed, the function will also check387 * that the product ID is as expected. This assumes that drivers providing388 * 'prod_id_reg' will also provide the 'prod_id'.389 *390 * Returns 0 if the device is operational, a negative error code otherwise.391 *392 * This function should be called early on in the device initialization sequence393 * to ensure that the device is in a sane and known state and that it is usable.394 */395int __adis_initial_startup(struct adis *adis)396{397	const struct adis_timeout *timeouts = adis->data->timeouts;398	struct gpio_desc *gpio;399	u16 prod_id;400	int ret;401 402	/* check if the device has rst pin low */403	gpio = devm_gpiod_get_optional(&adis->spi->dev, "reset", GPIOD_OUT_HIGH);404	if (IS_ERR(gpio))405		return PTR_ERR(gpio);406 407	if (gpio) {408		usleep_range(10, 12);409		/* bring device out of reset */410		gpiod_set_value_cansleep(gpio, 0);411		msleep(timeouts->reset_ms);412	} else {413		ret = __adis_reset(adis);414		if (ret)415			return ret;416	}417 418	ret = adis_self_test(adis);419	if (ret)420		return ret;421 422	/*423	 * don't bother calling this if we can't unmask the IRQ as in this case424	 * the IRQ is most likely not yet requested and we will request it425	 * with 'IRQF_NO_AUTOEN' anyways.426	 */427	if (!adis->data->unmasked_drdy)428		__adis_enable_irq(adis, false);429 430	if (!adis->data->prod_id_reg)431		return 0;432 433	ret = adis_read_reg_16(adis, adis->data->prod_id_reg, &prod_id);434	if (ret)435		return ret;436 437	if (prod_id != adis->data->prod_id)438		dev_warn(&adis->spi->dev,439			 "Device ID(%u) and product ID(%u) do not match.\n",440			 adis->data->prod_id, prod_id);441 442	return 0;443}444EXPORT_SYMBOL_NS_GPL(__adis_initial_startup, IIO_ADISLIB);445 446/**447 * adis_single_conversion() - Performs a single sample conversion448 * @indio_dev: The IIO device449 * @chan: The IIO channel450 * @error_mask: Mask for the error bit451 * @val: Result of the conversion452 *453 * Returns IIO_VAL_INT on success, a negative error code otherwise.454 *455 * The function performs a single conversion on a given channel and post456 * processes the value accordingly to the channel spec. If a error_mask is given457 * the function will check if the mask is set in the returned raw value. If it458 * is set the function will perform a self-check. If the device does not report459 * a error bit in the channels raw value set error_mask to 0.460 */461int adis_single_conversion(struct iio_dev *indio_dev,462			   const struct iio_chan_spec *chan,463			   unsigned int error_mask, int *val)464{465	struct adis *adis = iio_device_get_drvdata(indio_dev);466	unsigned int uval;467	int ret;468 469	guard(mutex)(&adis->state_lock);470 471	ret = __adis_read_reg(adis, chan->address, &uval,472			      chan->scan_type.storagebits / 8);473	if (ret)474		return ret;475 476	if (uval & error_mask) {477		ret = __adis_check_status(adis);478		if (ret)479			return ret;480	}481 482	if (chan->scan_type.sign == 's')483		*val = sign_extend32(uval, chan->scan_type.realbits - 1);484	else485		*val = uval & ((1 << chan->scan_type.realbits) - 1);486 487	return IIO_VAL_INT;488}489EXPORT_SYMBOL_NS_GPL(adis_single_conversion, IIO_ADISLIB);490 491/**492 * adis_init() - Initialize adis device structure493 * @adis:	The adis device494 * @indio_dev:	The iio device495 * @spi:	The spi device496 * @data:	Chip specific data497 *498 * Returns 0 on success, a negative error code otherwise.499 *500 * This function must be called, before any other adis helper function may be501 * called.502 */503int adis_init(struct adis *adis, struct iio_dev *indio_dev,504	      struct spi_device *spi, const struct adis_data *data)505{506	if (!data || !data->timeouts) {507		dev_err(&spi->dev, "No config data or timeouts not defined!\n");508		return -EINVAL;509	}510 511	mutex_init(&adis->state_lock);512 513	if (!spi->cs_inactive.value) {514		spi->cs_inactive.value = data->cs_change_delay;515		spi->cs_inactive.unit = SPI_DELAY_UNIT_USECS;516	}517 518	adis->spi = spi;519	adis->data = data;520	iio_device_set_drvdata(indio_dev, adis);521 522	if (data->has_paging) {523		/* Need to set the page before first read/write */524		adis->current_page = -1;525	} else {526		/* Page will always be 0 */527		adis->current_page = 0;528	}529 530	return 0;531}532EXPORT_SYMBOL_NS_GPL(adis_init, IIO_ADISLIB);533 534MODULE_LICENSE("GPL");535MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");536MODULE_DESCRIPTION("Common library code for ADIS16XXX devices");537