162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Murata SCA3300 3-axis industrial accelerometer 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2021 Vaisala Oyj. All rights reserved. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/bitops.h> 962306a36Sopenharmony_ci#include <linux/crc8.h> 1062306a36Sopenharmony_ci#include <linux/delay.h> 1162306a36Sopenharmony_ci#include <linux/kernel.h> 1262306a36Sopenharmony_ci#include <linux/module.h> 1362306a36Sopenharmony_ci#include <linux/spi/spi.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include <asm/unaligned.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include <linux/iio/buffer.h> 1862306a36Sopenharmony_ci#include <linux/iio/iio.h> 1962306a36Sopenharmony_ci#include <linux/iio/sysfs.h> 2062306a36Sopenharmony_ci#include <linux/iio/trigger_consumer.h> 2162306a36Sopenharmony_ci#include <linux/iio/triggered_buffer.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#define SCA3300_ALIAS "sca3300" 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#define SCA3300_CRC8_POLYNOMIAL 0x1d 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci/* Device mode register */ 2862306a36Sopenharmony_ci#define SCA3300_REG_MODE 0xd 2962306a36Sopenharmony_ci#define SCA3300_MODE_SW_RESET 0x20 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci/* Last register in map */ 3262306a36Sopenharmony_ci#define SCA3300_REG_SELBANK 0x1f 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci/* Device status and mask */ 3562306a36Sopenharmony_ci#define SCA3300_REG_STATUS 0x6 3662306a36Sopenharmony_ci#define SCA3300_STATUS_MASK GENMASK(8, 0) 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci/* Device ID */ 3962306a36Sopenharmony_ci#define SCA3300_REG_WHOAMI 0x10 4062306a36Sopenharmony_ci#define SCA3300_WHOAMI_ID 0x51 4162306a36Sopenharmony_ci#define SCL3300_WHOAMI_ID 0xC1 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci/* Device return status and mask */ 4462306a36Sopenharmony_ci#define SCA3300_VALUE_RS_ERROR 0x3 4562306a36Sopenharmony_ci#define SCA3300_MASK_RS_STATUS GENMASK(1, 0) 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci#define SCL3300_REG_ANG_CTRL 0x0C 4862306a36Sopenharmony_ci#define SCL3300_ANG_ENABLE 0x1F 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cienum sca3300_scan_indexes { 5162306a36Sopenharmony_ci SCA3300_ACC_X = 0, 5262306a36Sopenharmony_ci SCA3300_ACC_Y, 5362306a36Sopenharmony_ci SCA3300_ACC_Z, 5462306a36Sopenharmony_ci SCA3300_TEMP, 5562306a36Sopenharmony_ci SCA3300_INCLI_X, 5662306a36Sopenharmony_ci SCA3300_INCLI_Y, 5762306a36Sopenharmony_ci SCA3300_INCLI_Z, 5862306a36Sopenharmony_ci SCA3300_SCAN_MAX 5962306a36Sopenharmony_ci}; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci/* 6262306a36Sopenharmony_ci * Buffer size max case: 6362306a36Sopenharmony_ci * Three accel channels, two bytes per channel. 6462306a36Sopenharmony_ci * Temperature channel, two bytes. 6562306a36Sopenharmony_ci * Three incli channels, two bytes per channel. 6662306a36Sopenharmony_ci * Timestamp channel, eight bytes. 6762306a36Sopenharmony_ci */ 6862306a36Sopenharmony_ci#define SCA3300_MAX_BUFFER_SIZE (ALIGN(sizeof(s16) * SCA3300_SCAN_MAX, sizeof(s64)) + sizeof(s64)) 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci#define SCA3300_ACCEL_CHANNEL(index, reg, axis) { \ 7162306a36Sopenharmony_ci .type = IIO_ACCEL, \ 7262306a36Sopenharmony_ci .address = reg, \ 7362306a36Sopenharmony_ci .modified = 1, \ 7462306a36Sopenharmony_ci .channel2 = IIO_MOD_##axis, \ 7562306a36Sopenharmony_ci .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ 7662306a36Sopenharmony_ci .info_mask_shared_by_type = \ 7762306a36Sopenharmony_ci BIT(IIO_CHAN_INFO_SCALE) | \ 7862306a36Sopenharmony_ci BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \ 7962306a36Sopenharmony_ci .info_mask_shared_by_type_available = \ 8062306a36Sopenharmony_ci BIT(IIO_CHAN_INFO_SCALE) | \ 8162306a36Sopenharmony_ci BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \ 8262306a36Sopenharmony_ci .scan_index = index, \ 8362306a36Sopenharmony_ci .scan_type = { \ 8462306a36Sopenharmony_ci .sign = 's', \ 8562306a36Sopenharmony_ci .realbits = 16, \ 8662306a36Sopenharmony_ci .storagebits = 16, \ 8762306a36Sopenharmony_ci .endianness = IIO_CPU, \ 8862306a36Sopenharmony_ci }, \ 8962306a36Sopenharmony_ci} 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci#define SCA3300_INCLI_CHANNEL(index, reg, axis) { \ 9262306a36Sopenharmony_ci .type = IIO_INCLI, \ 9362306a36Sopenharmony_ci .address = reg, \ 9462306a36Sopenharmony_ci .modified = 1, \ 9562306a36Sopenharmony_ci .channel2 = IIO_MOD_##axis, \ 9662306a36Sopenharmony_ci .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ 9762306a36Sopenharmony_ci .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ 9862306a36Sopenharmony_ci .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SCALE), \ 9962306a36Sopenharmony_ci .scan_index = index, \ 10062306a36Sopenharmony_ci .scan_type = { \ 10162306a36Sopenharmony_ci .sign = 's', \ 10262306a36Sopenharmony_ci .realbits = 16, \ 10362306a36Sopenharmony_ci .storagebits = 16, \ 10462306a36Sopenharmony_ci .endianness = IIO_CPU, \ 10562306a36Sopenharmony_ci }, \ 10662306a36Sopenharmony_ci} 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci#define SCA3300_TEMP_CHANNEL(index, reg) { \ 10962306a36Sopenharmony_ci .type = IIO_TEMP, \ 11062306a36Sopenharmony_ci .address = reg, \ 11162306a36Sopenharmony_ci .scan_index = index, \ 11262306a36Sopenharmony_ci .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ 11362306a36Sopenharmony_ci .scan_type = { \ 11462306a36Sopenharmony_ci .sign = 's', \ 11562306a36Sopenharmony_ci .realbits = 16, \ 11662306a36Sopenharmony_ci .storagebits = 16, \ 11762306a36Sopenharmony_ci .endianness = IIO_CPU, \ 11862306a36Sopenharmony_ci }, \ 11962306a36Sopenharmony_ci} 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_cistatic const struct iio_chan_spec sca3300_channels[] = { 12262306a36Sopenharmony_ci SCA3300_ACCEL_CHANNEL(SCA3300_ACC_X, 0x1, X), 12362306a36Sopenharmony_ci SCA3300_ACCEL_CHANNEL(SCA3300_ACC_Y, 0x2, Y), 12462306a36Sopenharmony_ci SCA3300_ACCEL_CHANNEL(SCA3300_ACC_Z, 0x3, Z), 12562306a36Sopenharmony_ci SCA3300_TEMP_CHANNEL(SCA3300_TEMP, 0x05), 12662306a36Sopenharmony_ci IIO_CHAN_SOFT_TIMESTAMP(4), 12762306a36Sopenharmony_ci}; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_cistatic const int sca3300_lp_freq[] = {70, 10}; 13062306a36Sopenharmony_cistatic const int sca3300_lp_freq_map[] = {0, 0, 0, 1}; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_cistatic const int scl3300_lp_freq[] = {40, 70, 10}; 13362306a36Sopenharmony_cistatic const int scl3300_lp_freq_map[] = {0, 1, 2}; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_cistatic const int sca3300_accel_scale[][2] = {{0, 370}, {0, 741}, {0, 185}}; 13662306a36Sopenharmony_cistatic const int sca3300_accel_scale_map[] = {0, 1, 2, 2}; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_cistatic const int scl3300_accel_scale[][2] = {{0, 167}, {0, 333}, {0, 83}}; 13962306a36Sopenharmony_cistatic const int scl3300_accel_scale_map[] = {0, 1, 2}; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_cistatic const int scl3300_incli_scale[][2] = {{0, 5495}}; 14262306a36Sopenharmony_cistatic const int scl3300_incli_scale_map[] = {0, 0, 0}; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_cistatic const int sca3300_avail_modes_map[] = {0, 1, 2, 3}; 14562306a36Sopenharmony_cistatic const int scl3300_avail_modes_map[] = {0, 1, 3}; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_cistatic const struct iio_chan_spec scl3300_channels[] = { 14862306a36Sopenharmony_ci SCA3300_ACCEL_CHANNEL(SCA3300_ACC_X, 0x1, X), 14962306a36Sopenharmony_ci SCA3300_ACCEL_CHANNEL(SCA3300_ACC_Y, 0x2, Y), 15062306a36Sopenharmony_ci SCA3300_ACCEL_CHANNEL(SCA3300_ACC_Z, 0x3, Z), 15162306a36Sopenharmony_ci SCA3300_TEMP_CHANNEL(SCA3300_TEMP, 0x05), 15262306a36Sopenharmony_ci SCA3300_INCLI_CHANNEL(SCA3300_INCLI_X, 0x09, X), 15362306a36Sopenharmony_ci SCA3300_INCLI_CHANNEL(SCA3300_INCLI_Y, 0x0A, Y), 15462306a36Sopenharmony_ci SCA3300_INCLI_CHANNEL(SCA3300_INCLI_Z, 0x0B, Z), 15562306a36Sopenharmony_ci IIO_CHAN_SOFT_TIMESTAMP(7), 15662306a36Sopenharmony_ci}; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_cistatic const unsigned long sca3300_scan_masks[] = { 15962306a36Sopenharmony_ci BIT(SCA3300_ACC_X) | BIT(SCA3300_ACC_Y) | BIT(SCA3300_ACC_Z) | 16062306a36Sopenharmony_ci BIT(SCA3300_TEMP), 16162306a36Sopenharmony_ci 0 16262306a36Sopenharmony_ci}; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_cistatic const unsigned long scl3300_scan_masks[] = { 16562306a36Sopenharmony_ci BIT(SCA3300_ACC_X) | BIT(SCA3300_ACC_Y) | BIT(SCA3300_ACC_Z) | 16662306a36Sopenharmony_ci BIT(SCA3300_TEMP) | 16762306a36Sopenharmony_ci BIT(SCA3300_INCLI_X) | BIT(SCA3300_INCLI_Y) | BIT(SCA3300_INCLI_Z), 16862306a36Sopenharmony_ci 0 16962306a36Sopenharmony_ci}; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_cistruct sca3300_chip_info { 17262306a36Sopenharmony_ci const char *name; 17362306a36Sopenharmony_ci const unsigned long *scan_masks; 17462306a36Sopenharmony_ci const struct iio_chan_spec *channels; 17562306a36Sopenharmony_ci u8 num_channels; 17662306a36Sopenharmony_ci u8 num_accel_scales; 17762306a36Sopenharmony_ci const int (*accel_scale)[2]; 17862306a36Sopenharmony_ci const int *accel_scale_map; 17962306a36Sopenharmony_ci const int (*incli_scale)[2]; 18062306a36Sopenharmony_ci const int *incli_scale_map; 18162306a36Sopenharmony_ci u8 num_incli_scales; 18262306a36Sopenharmony_ci u8 num_freqs; 18362306a36Sopenharmony_ci const int *freq_table; 18462306a36Sopenharmony_ci const int *freq_map; 18562306a36Sopenharmony_ci const int *avail_modes_table; 18662306a36Sopenharmony_ci u8 num_avail_modes; 18762306a36Sopenharmony_ci u8 chip_id; 18862306a36Sopenharmony_ci bool angle_supported; 18962306a36Sopenharmony_ci}; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci/** 19262306a36Sopenharmony_ci * struct sca3300_data - device data 19362306a36Sopenharmony_ci * @spi: SPI device structure 19462306a36Sopenharmony_ci * @lock: Data buffer lock 19562306a36Sopenharmony_ci * @chip: Sensor chip specific information 19662306a36Sopenharmony_ci * @buffer: Triggered buffer: 19762306a36Sopenharmony_ci * -SCA3300: 4 channel 16-bit data + 64-bit timestamp 19862306a36Sopenharmony_ci * -SCL3300: 7 channel 16-bit data + 64-bit timestamp 19962306a36Sopenharmony_ci * @txbuf: Transmit buffer 20062306a36Sopenharmony_ci * @rxbuf: Receive buffer 20162306a36Sopenharmony_ci */ 20262306a36Sopenharmony_cistruct sca3300_data { 20362306a36Sopenharmony_ci struct spi_device *spi; 20462306a36Sopenharmony_ci struct mutex lock; 20562306a36Sopenharmony_ci const struct sca3300_chip_info *chip; 20662306a36Sopenharmony_ci u8 buffer[SCA3300_MAX_BUFFER_SIZE] __aligned(sizeof(s64)); 20762306a36Sopenharmony_ci u8 txbuf[4] __aligned(IIO_DMA_MINALIGN); 20862306a36Sopenharmony_ci u8 rxbuf[4]; 20962306a36Sopenharmony_ci}; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_cistatic const struct sca3300_chip_info sca3300_chip_tbl[] = { 21262306a36Sopenharmony_ci { 21362306a36Sopenharmony_ci .name = "sca3300", 21462306a36Sopenharmony_ci .scan_masks = sca3300_scan_masks, 21562306a36Sopenharmony_ci .channels = sca3300_channels, 21662306a36Sopenharmony_ci .num_channels = ARRAY_SIZE(sca3300_channels), 21762306a36Sopenharmony_ci .num_accel_scales = ARRAY_SIZE(sca3300_accel_scale)*2, 21862306a36Sopenharmony_ci .accel_scale = sca3300_accel_scale, 21962306a36Sopenharmony_ci .accel_scale_map = sca3300_accel_scale_map, 22062306a36Sopenharmony_ci .num_freqs = ARRAY_SIZE(sca3300_lp_freq), 22162306a36Sopenharmony_ci .freq_table = sca3300_lp_freq, 22262306a36Sopenharmony_ci .freq_map = sca3300_lp_freq_map, 22362306a36Sopenharmony_ci .avail_modes_table = sca3300_avail_modes_map, 22462306a36Sopenharmony_ci .num_avail_modes = 4, 22562306a36Sopenharmony_ci .chip_id = SCA3300_WHOAMI_ID, 22662306a36Sopenharmony_ci .angle_supported = false, 22762306a36Sopenharmony_ci }, 22862306a36Sopenharmony_ci { 22962306a36Sopenharmony_ci .name = "scl3300", 23062306a36Sopenharmony_ci .scan_masks = scl3300_scan_masks, 23162306a36Sopenharmony_ci .channels = scl3300_channels, 23262306a36Sopenharmony_ci .num_channels = ARRAY_SIZE(scl3300_channels), 23362306a36Sopenharmony_ci .num_accel_scales = ARRAY_SIZE(scl3300_accel_scale)*2, 23462306a36Sopenharmony_ci .accel_scale = scl3300_accel_scale, 23562306a36Sopenharmony_ci .accel_scale_map = scl3300_accel_scale_map, 23662306a36Sopenharmony_ci .incli_scale = scl3300_incli_scale, 23762306a36Sopenharmony_ci .incli_scale_map = scl3300_incli_scale_map, 23862306a36Sopenharmony_ci .num_incli_scales = ARRAY_SIZE(scl3300_incli_scale)*2, 23962306a36Sopenharmony_ci .num_freqs = ARRAY_SIZE(scl3300_lp_freq), 24062306a36Sopenharmony_ci .freq_table = scl3300_lp_freq, 24162306a36Sopenharmony_ci .freq_map = scl3300_lp_freq_map, 24262306a36Sopenharmony_ci .avail_modes_table = scl3300_avail_modes_map, 24362306a36Sopenharmony_ci .num_avail_modes = 3, 24462306a36Sopenharmony_ci .chip_id = SCL3300_WHOAMI_ID, 24562306a36Sopenharmony_ci .angle_supported = true, 24662306a36Sopenharmony_ci }, 24762306a36Sopenharmony_ci}; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ciDECLARE_CRC8_TABLE(sca3300_crc_table); 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_cistatic int sca3300_transfer(struct sca3300_data *sca_data, int *val) 25262306a36Sopenharmony_ci{ 25362306a36Sopenharmony_ci /* Consecutive requests min. 10 us delay (Datasheet section 5.1.2) */ 25462306a36Sopenharmony_ci struct spi_delay delay = { .value = 10, .unit = SPI_DELAY_UNIT_USECS }; 25562306a36Sopenharmony_ci int32_t ret; 25662306a36Sopenharmony_ci int rs; 25762306a36Sopenharmony_ci u8 crc; 25862306a36Sopenharmony_ci struct spi_transfer xfers[2] = { 25962306a36Sopenharmony_ci { 26062306a36Sopenharmony_ci .tx_buf = sca_data->txbuf, 26162306a36Sopenharmony_ci .len = ARRAY_SIZE(sca_data->txbuf), 26262306a36Sopenharmony_ci .delay = delay, 26362306a36Sopenharmony_ci .cs_change = 1, 26462306a36Sopenharmony_ci }, 26562306a36Sopenharmony_ci { 26662306a36Sopenharmony_ci .rx_buf = sca_data->rxbuf, 26762306a36Sopenharmony_ci .len = ARRAY_SIZE(sca_data->rxbuf), 26862306a36Sopenharmony_ci .delay = delay, 26962306a36Sopenharmony_ci } 27062306a36Sopenharmony_ci }; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci /* inverted crc value as described in device data sheet */ 27362306a36Sopenharmony_ci crc = ~crc8(sca3300_crc_table, &sca_data->txbuf[0], 3, CRC8_INIT_VALUE); 27462306a36Sopenharmony_ci sca_data->txbuf[3] = crc; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci ret = spi_sync_transfer(sca_data->spi, xfers, ARRAY_SIZE(xfers)); 27762306a36Sopenharmony_ci if (ret) { 27862306a36Sopenharmony_ci dev_err(&sca_data->spi->dev, 27962306a36Sopenharmony_ci "transfer error, error: %d\n", ret); 28062306a36Sopenharmony_ci return -EIO; 28162306a36Sopenharmony_ci } 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci crc = ~crc8(sca3300_crc_table, &sca_data->rxbuf[0], 3, CRC8_INIT_VALUE); 28462306a36Sopenharmony_ci if (sca_data->rxbuf[3] != crc) { 28562306a36Sopenharmony_ci dev_err(&sca_data->spi->dev, "CRC checksum mismatch"); 28662306a36Sopenharmony_ci return -EIO; 28762306a36Sopenharmony_ci } 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci /* get return status */ 29062306a36Sopenharmony_ci rs = sca_data->rxbuf[0] & SCA3300_MASK_RS_STATUS; 29162306a36Sopenharmony_ci if (rs == SCA3300_VALUE_RS_ERROR) 29262306a36Sopenharmony_ci ret = -EINVAL; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci *val = sign_extend32(get_unaligned_be16(&sca_data->rxbuf[1]), 15); 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci return ret; 29762306a36Sopenharmony_ci} 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_cistatic int sca3300_error_handler(struct sca3300_data *sca_data) 30062306a36Sopenharmony_ci{ 30162306a36Sopenharmony_ci int ret; 30262306a36Sopenharmony_ci int val; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci mutex_lock(&sca_data->lock); 30562306a36Sopenharmony_ci sca_data->txbuf[0] = SCA3300_REG_STATUS << 2; 30662306a36Sopenharmony_ci ret = sca3300_transfer(sca_data, &val); 30762306a36Sopenharmony_ci mutex_unlock(&sca_data->lock); 30862306a36Sopenharmony_ci /* 30962306a36Sopenharmony_ci * Return status error is cleared after reading status register once, 31062306a36Sopenharmony_ci * expect EINVAL here. 31162306a36Sopenharmony_ci */ 31262306a36Sopenharmony_ci if (ret != -EINVAL) { 31362306a36Sopenharmony_ci dev_err(&sca_data->spi->dev, 31462306a36Sopenharmony_ci "error reading device status: %d\n", ret); 31562306a36Sopenharmony_ci return ret; 31662306a36Sopenharmony_ci } 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci dev_err(&sca_data->spi->dev, "device status: 0x%lx\n", 31962306a36Sopenharmony_ci val & SCA3300_STATUS_MASK); 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci return 0; 32262306a36Sopenharmony_ci} 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_cistatic int sca3300_read_reg(struct sca3300_data *sca_data, u8 reg, int *val) 32562306a36Sopenharmony_ci{ 32662306a36Sopenharmony_ci int ret; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci mutex_lock(&sca_data->lock); 32962306a36Sopenharmony_ci sca_data->txbuf[0] = reg << 2; 33062306a36Sopenharmony_ci ret = sca3300_transfer(sca_data, val); 33162306a36Sopenharmony_ci mutex_unlock(&sca_data->lock); 33262306a36Sopenharmony_ci if (ret != -EINVAL) 33362306a36Sopenharmony_ci return ret; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci return sca3300_error_handler(sca_data); 33662306a36Sopenharmony_ci} 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_cistatic int sca3300_write_reg(struct sca3300_data *sca_data, u8 reg, int val) 33962306a36Sopenharmony_ci{ 34062306a36Sopenharmony_ci int reg_val = 0; 34162306a36Sopenharmony_ci int ret; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci mutex_lock(&sca_data->lock); 34462306a36Sopenharmony_ci /* BIT(7) for write operation */ 34562306a36Sopenharmony_ci sca_data->txbuf[0] = BIT(7) | (reg << 2); 34662306a36Sopenharmony_ci put_unaligned_be16(val, &sca_data->txbuf[1]); 34762306a36Sopenharmony_ci ret = sca3300_transfer(sca_data, ®_val); 34862306a36Sopenharmony_ci mutex_unlock(&sca_data->lock); 34962306a36Sopenharmony_ci if (ret != -EINVAL) 35062306a36Sopenharmony_ci return ret; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci return sca3300_error_handler(sca_data); 35362306a36Sopenharmony_ci} 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_cistatic int sca3300_set_op_mode(struct sca3300_data *sca_data, int index) 35662306a36Sopenharmony_ci{ 35762306a36Sopenharmony_ci if ((index < 0) || (index >= sca_data->chip->num_avail_modes)) 35862306a36Sopenharmony_ci return -EINVAL; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci return sca3300_write_reg(sca_data, SCA3300_REG_MODE, 36162306a36Sopenharmony_ci sca_data->chip->avail_modes_table[index]); 36262306a36Sopenharmony_ci} 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_cistatic int sca3300_get_op_mode(struct sca3300_data *sca_data, int *index) 36562306a36Sopenharmony_ci{ 36662306a36Sopenharmony_ci int reg_val; 36762306a36Sopenharmony_ci int ret; 36862306a36Sopenharmony_ci int i; 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci ret = sca3300_read_reg(sca_data, SCA3300_REG_MODE, ®_val); 37162306a36Sopenharmony_ci if (ret) 37262306a36Sopenharmony_ci return ret; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci for (i = 0; i < sca_data->chip->num_avail_modes; i++) { 37562306a36Sopenharmony_ci if (sca_data->chip->avail_modes_table[i] == reg_val) 37662306a36Sopenharmony_ci break; 37762306a36Sopenharmony_ci } 37862306a36Sopenharmony_ci if (i == sca_data->chip->num_avail_modes) 37962306a36Sopenharmony_ci return -EINVAL; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci *index = i; 38262306a36Sopenharmony_ci return 0; 38362306a36Sopenharmony_ci} 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_cistatic int sca3300_set_frequency(struct sca3300_data *data, int val) 38662306a36Sopenharmony_ci{ 38762306a36Sopenharmony_ci const struct sca3300_chip_info *chip = data->chip; 38862306a36Sopenharmony_ci unsigned int index; 38962306a36Sopenharmony_ci int *opmode_scale; 39062306a36Sopenharmony_ci int *new_scale; 39162306a36Sopenharmony_ci unsigned int i; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci if (sca3300_get_op_mode(data, &index)) 39462306a36Sopenharmony_ci return -EINVAL; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci /* 39762306a36Sopenharmony_ci * Find a mode in which the requested sampling frequency is available 39862306a36Sopenharmony_ci * and the scaling currently set is retained. 39962306a36Sopenharmony_ci */ 40062306a36Sopenharmony_ci opmode_scale = (int *)chip->accel_scale[chip->accel_scale_map[index]]; 40162306a36Sopenharmony_ci for (i = 0; i < chip->num_avail_modes; i++) { 40262306a36Sopenharmony_ci new_scale = (int *)chip->accel_scale[chip->accel_scale_map[i]]; 40362306a36Sopenharmony_ci if ((val == chip->freq_table[chip->freq_map[i]]) && 40462306a36Sopenharmony_ci (opmode_scale[1] == new_scale[1]) && 40562306a36Sopenharmony_ci (opmode_scale[0] == new_scale[0])) 40662306a36Sopenharmony_ci break; 40762306a36Sopenharmony_ci } 40862306a36Sopenharmony_ci if (i == chip->num_avail_modes) 40962306a36Sopenharmony_ci return -EINVAL; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci return sca3300_set_op_mode(data, i); 41262306a36Sopenharmony_ci} 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_cistatic int sca3300_write_raw(struct iio_dev *indio_dev, 41562306a36Sopenharmony_ci struct iio_chan_spec const *chan, 41662306a36Sopenharmony_ci int val, int val2, long mask) 41762306a36Sopenharmony_ci{ 41862306a36Sopenharmony_ci struct sca3300_data *data = iio_priv(indio_dev); 41962306a36Sopenharmony_ci int index; 42062306a36Sopenharmony_ci int i; 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci switch (mask) { 42362306a36Sopenharmony_ci case IIO_CHAN_INFO_SCALE: 42462306a36Sopenharmony_ci if (chan->type != IIO_ACCEL) 42562306a36Sopenharmony_ci return -EINVAL; 42662306a36Sopenharmony_ci /* 42762306a36Sopenharmony_ci * Letting scale take priority over sampling frequency. 42862306a36Sopenharmony_ci * That makes sense given we can only ever end up increasing 42962306a36Sopenharmony_ci * the sampling frequency which is unlikely to be a problem. 43062306a36Sopenharmony_ci */ 43162306a36Sopenharmony_ci for (i = 0; i < data->chip->num_avail_modes; i++) { 43262306a36Sopenharmony_ci index = data->chip->accel_scale_map[i]; 43362306a36Sopenharmony_ci if ((val == data->chip->accel_scale[index][0]) && 43462306a36Sopenharmony_ci (val2 == data->chip->accel_scale[index][1])) 43562306a36Sopenharmony_ci return sca3300_set_op_mode(data, i); 43662306a36Sopenharmony_ci } 43762306a36Sopenharmony_ci return -EINVAL; 43862306a36Sopenharmony_ci case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: 43962306a36Sopenharmony_ci return sca3300_set_frequency(data, val); 44062306a36Sopenharmony_ci default: 44162306a36Sopenharmony_ci return -EINVAL; 44262306a36Sopenharmony_ci } 44362306a36Sopenharmony_ci} 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_cistatic int sca3300_read_raw(struct iio_dev *indio_dev, 44662306a36Sopenharmony_ci struct iio_chan_spec const *chan, 44762306a36Sopenharmony_ci int *val, int *val2, long mask) 44862306a36Sopenharmony_ci{ 44962306a36Sopenharmony_ci struct sca3300_data *data = iio_priv(indio_dev); 45062306a36Sopenharmony_ci int index; 45162306a36Sopenharmony_ci int ret; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci switch (mask) { 45462306a36Sopenharmony_ci case IIO_CHAN_INFO_RAW: 45562306a36Sopenharmony_ci ret = sca3300_read_reg(data, chan->address, val); 45662306a36Sopenharmony_ci if (ret) 45762306a36Sopenharmony_ci return ret; 45862306a36Sopenharmony_ci return IIO_VAL_INT; 45962306a36Sopenharmony_ci case IIO_CHAN_INFO_SCALE: 46062306a36Sopenharmony_ci ret = sca3300_get_op_mode(data, &index); 46162306a36Sopenharmony_ci if (ret) 46262306a36Sopenharmony_ci return ret; 46362306a36Sopenharmony_ci switch (chan->type) { 46462306a36Sopenharmony_ci case IIO_INCLI: 46562306a36Sopenharmony_ci index = data->chip->incli_scale_map[index]; 46662306a36Sopenharmony_ci *val = data->chip->incli_scale[index][0]; 46762306a36Sopenharmony_ci *val2 = data->chip->incli_scale[index][1]; 46862306a36Sopenharmony_ci return IIO_VAL_INT_PLUS_MICRO; 46962306a36Sopenharmony_ci case IIO_ACCEL: 47062306a36Sopenharmony_ci index = data->chip->accel_scale_map[index]; 47162306a36Sopenharmony_ci *val = data->chip->accel_scale[index][0]; 47262306a36Sopenharmony_ci *val2 = data->chip->accel_scale[index][1]; 47362306a36Sopenharmony_ci return IIO_VAL_INT_PLUS_MICRO; 47462306a36Sopenharmony_ci default: 47562306a36Sopenharmony_ci return -EINVAL; 47662306a36Sopenharmony_ci } 47762306a36Sopenharmony_ci case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: 47862306a36Sopenharmony_ci ret = sca3300_get_op_mode(data, &index); 47962306a36Sopenharmony_ci if (ret) 48062306a36Sopenharmony_ci return ret; 48162306a36Sopenharmony_ci index = data->chip->freq_map[index]; 48262306a36Sopenharmony_ci *val = data->chip->freq_table[index]; 48362306a36Sopenharmony_ci return IIO_VAL_INT; 48462306a36Sopenharmony_ci default: 48562306a36Sopenharmony_ci return -EINVAL; 48662306a36Sopenharmony_ci } 48762306a36Sopenharmony_ci} 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_cistatic irqreturn_t sca3300_trigger_handler(int irq, void *p) 49062306a36Sopenharmony_ci{ 49162306a36Sopenharmony_ci struct iio_poll_func *pf = p; 49262306a36Sopenharmony_ci struct iio_dev *indio_dev = pf->indio_dev; 49362306a36Sopenharmony_ci struct sca3300_data *data = iio_priv(indio_dev); 49462306a36Sopenharmony_ci int bit, ret, val, i = 0; 49562306a36Sopenharmony_ci s16 *channels = (s16 *)data->buffer; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci for_each_set_bit(bit, indio_dev->active_scan_mask, 49862306a36Sopenharmony_ci indio_dev->masklength) { 49962306a36Sopenharmony_ci ret = sca3300_read_reg(data, indio_dev->channels[bit].address, &val); 50062306a36Sopenharmony_ci if (ret) { 50162306a36Sopenharmony_ci dev_err_ratelimited(&data->spi->dev, 50262306a36Sopenharmony_ci "failed to read register, error: %d\n", ret); 50362306a36Sopenharmony_ci /* handled, but bailing out due to errors */ 50462306a36Sopenharmony_ci goto out; 50562306a36Sopenharmony_ci } 50662306a36Sopenharmony_ci channels[i++] = val; 50762306a36Sopenharmony_ci } 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, 51062306a36Sopenharmony_ci iio_get_time_ns(indio_dev)); 51162306a36Sopenharmony_ciout: 51262306a36Sopenharmony_ci iio_trigger_notify_done(indio_dev->trig); 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci return IRQ_HANDLED; 51562306a36Sopenharmony_ci} 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci/* 51862306a36Sopenharmony_ci * sca3300_init - Device init sequence. See datasheet rev 2 section 51962306a36Sopenharmony_ci * 4.2 Start-Up Sequence for details. 52062306a36Sopenharmony_ci */ 52162306a36Sopenharmony_cistatic int sca3300_init(struct sca3300_data *sca_data, 52262306a36Sopenharmony_ci struct iio_dev *indio_dev) 52362306a36Sopenharmony_ci{ 52462306a36Sopenharmony_ci int value = 0; 52562306a36Sopenharmony_ci int ret; 52662306a36Sopenharmony_ci int i; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci ret = sca3300_write_reg(sca_data, SCA3300_REG_MODE, 52962306a36Sopenharmony_ci SCA3300_MODE_SW_RESET); 53062306a36Sopenharmony_ci if (ret) 53162306a36Sopenharmony_ci return ret; 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci /* 53462306a36Sopenharmony_ci * Wait 1ms after SW-reset command. 53562306a36Sopenharmony_ci * Wait for the settling of signal paths, 53662306a36Sopenharmony_ci * 15ms for SCA3300 and 25ms for SCL3300, 53762306a36Sopenharmony_ci */ 53862306a36Sopenharmony_ci usleep_range(26e3, 50e3); 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci ret = sca3300_read_reg(sca_data, SCA3300_REG_WHOAMI, &value); 54162306a36Sopenharmony_ci if (ret) 54262306a36Sopenharmony_ci return ret; 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(sca3300_chip_tbl); i++) { 54562306a36Sopenharmony_ci if (sca3300_chip_tbl[i].chip_id == value) 54662306a36Sopenharmony_ci break; 54762306a36Sopenharmony_ci } 54862306a36Sopenharmony_ci if (i == ARRAY_SIZE(sca3300_chip_tbl)) { 54962306a36Sopenharmony_ci dev_err(&sca_data->spi->dev, "unknown chip id %x\n", value); 55062306a36Sopenharmony_ci return -ENODEV; 55162306a36Sopenharmony_ci } 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci sca_data->chip = &sca3300_chip_tbl[i]; 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci if (sca_data->chip->angle_supported) { 55662306a36Sopenharmony_ci ret = sca3300_write_reg(sca_data, SCL3300_REG_ANG_CTRL, 55762306a36Sopenharmony_ci SCL3300_ANG_ENABLE); 55862306a36Sopenharmony_ci if (ret) 55962306a36Sopenharmony_ci return ret; 56062306a36Sopenharmony_ci } 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci return 0; 56362306a36Sopenharmony_ci} 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_cistatic int sca3300_debugfs_reg_access(struct iio_dev *indio_dev, 56662306a36Sopenharmony_ci unsigned int reg, unsigned int writeval, 56762306a36Sopenharmony_ci unsigned int *readval) 56862306a36Sopenharmony_ci{ 56962306a36Sopenharmony_ci struct sca3300_data *data = iio_priv(indio_dev); 57062306a36Sopenharmony_ci int value; 57162306a36Sopenharmony_ci int ret; 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci if (reg > SCA3300_REG_SELBANK) 57462306a36Sopenharmony_ci return -EINVAL; 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci if (!readval) 57762306a36Sopenharmony_ci return sca3300_write_reg(data, reg, writeval); 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci ret = sca3300_read_reg(data, reg, &value); 58062306a36Sopenharmony_ci if (ret) 58162306a36Sopenharmony_ci return ret; 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci *readval = value; 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci return 0; 58662306a36Sopenharmony_ci} 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_cistatic int sca3300_read_avail(struct iio_dev *indio_dev, 58962306a36Sopenharmony_ci struct iio_chan_spec const *chan, 59062306a36Sopenharmony_ci const int **vals, int *type, int *length, 59162306a36Sopenharmony_ci long mask) 59262306a36Sopenharmony_ci{ 59362306a36Sopenharmony_ci struct sca3300_data *data = iio_priv(indio_dev); 59462306a36Sopenharmony_ci switch (mask) { 59562306a36Sopenharmony_ci case IIO_CHAN_INFO_SCALE: 59662306a36Sopenharmony_ci switch (chan->type) { 59762306a36Sopenharmony_ci case IIO_INCLI: 59862306a36Sopenharmony_ci *vals = (const int *)data->chip->incli_scale; 59962306a36Sopenharmony_ci *length = data->chip->num_incli_scales; 60062306a36Sopenharmony_ci *type = IIO_VAL_INT_PLUS_MICRO; 60162306a36Sopenharmony_ci return IIO_AVAIL_LIST; 60262306a36Sopenharmony_ci case IIO_ACCEL: 60362306a36Sopenharmony_ci *vals = (const int *)data->chip->accel_scale; 60462306a36Sopenharmony_ci *length = data->chip->num_accel_scales; 60562306a36Sopenharmony_ci *type = IIO_VAL_INT_PLUS_MICRO; 60662306a36Sopenharmony_ci return IIO_AVAIL_LIST; 60762306a36Sopenharmony_ci default: 60862306a36Sopenharmony_ci return -EINVAL; 60962306a36Sopenharmony_ci } 61062306a36Sopenharmony_ci case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: 61162306a36Sopenharmony_ci *vals = (const int *)data->chip->freq_table; 61262306a36Sopenharmony_ci *length = data->chip->num_freqs; 61362306a36Sopenharmony_ci *type = IIO_VAL_INT; 61462306a36Sopenharmony_ci return IIO_AVAIL_LIST; 61562306a36Sopenharmony_ci default: 61662306a36Sopenharmony_ci return -EINVAL; 61762306a36Sopenharmony_ci } 61862306a36Sopenharmony_ci} 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_cistatic const struct iio_info sca3300_info = { 62162306a36Sopenharmony_ci .read_raw = sca3300_read_raw, 62262306a36Sopenharmony_ci .write_raw = sca3300_write_raw, 62362306a36Sopenharmony_ci .debugfs_reg_access = &sca3300_debugfs_reg_access, 62462306a36Sopenharmony_ci .read_avail = sca3300_read_avail, 62562306a36Sopenharmony_ci}; 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_cistatic int sca3300_probe(struct spi_device *spi) 62862306a36Sopenharmony_ci{ 62962306a36Sopenharmony_ci struct sca3300_data *sca_data; 63062306a36Sopenharmony_ci struct iio_dev *indio_dev; 63162306a36Sopenharmony_ci int ret; 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*sca_data)); 63462306a36Sopenharmony_ci if (!indio_dev) 63562306a36Sopenharmony_ci return -ENOMEM; 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci sca_data = iio_priv(indio_dev); 63862306a36Sopenharmony_ci mutex_init(&sca_data->lock); 63962306a36Sopenharmony_ci sca_data->spi = spi; 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci crc8_populate_msb(sca3300_crc_table, SCA3300_CRC8_POLYNOMIAL); 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci indio_dev->info = &sca3300_info; 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci ret = sca3300_init(sca_data, indio_dev); 64662306a36Sopenharmony_ci if (ret) { 64762306a36Sopenharmony_ci dev_err(&spi->dev, "failed to init device, error: %d\n", ret); 64862306a36Sopenharmony_ci return ret; 64962306a36Sopenharmony_ci } 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci indio_dev->name = sca_data->chip->name; 65262306a36Sopenharmony_ci indio_dev->modes = INDIO_DIRECT_MODE; 65362306a36Sopenharmony_ci indio_dev->channels = sca_data->chip->channels; 65462306a36Sopenharmony_ci indio_dev->num_channels = sca_data->chip->num_channels; 65562306a36Sopenharmony_ci indio_dev->available_scan_masks = sca_data->chip->scan_masks; 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, 65862306a36Sopenharmony_ci iio_pollfunc_store_time, 65962306a36Sopenharmony_ci sca3300_trigger_handler, NULL); 66062306a36Sopenharmony_ci if (ret) { 66162306a36Sopenharmony_ci dev_err(&spi->dev, 66262306a36Sopenharmony_ci "iio triggered buffer setup failed, error: %d\n", ret); 66362306a36Sopenharmony_ci return ret; 66462306a36Sopenharmony_ci } 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci ret = devm_iio_device_register(&spi->dev, indio_dev); 66762306a36Sopenharmony_ci if (ret) { 66862306a36Sopenharmony_ci dev_err(&spi->dev, "iio device register failed, error: %d\n", 66962306a36Sopenharmony_ci ret); 67062306a36Sopenharmony_ci } 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci return ret; 67362306a36Sopenharmony_ci} 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_cistatic const struct of_device_id sca3300_dt_ids[] = { 67662306a36Sopenharmony_ci { .compatible = "murata,sca3300"}, 67762306a36Sopenharmony_ci { .compatible = "murata,scl3300"}, 67862306a36Sopenharmony_ci {} 67962306a36Sopenharmony_ci}; 68062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, sca3300_dt_ids); 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_cistatic const struct spi_device_id sca3300_ids[] = { 68362306a36Sopenharmony_ci { "sca3300" }, 68462306a36Sopenharmony_ci { "scl3300" }, 68562306a36Sopenharmony_ci {} 68662306a36Sopenharmony_ci}; 68762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(spi, sca3300_ids); 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_cistatic struct spi_driver sca3300_driver = { 69062306a36Sopenharmony_ci .driver = { 69162306a36Sopenharmony_ci .name = SCA3300_ALIAS, 69262306a36Sopenharmony_ci .of_match_table = sca3300_dt_ids, 69362306a36Sopenharmony_ci }, 69462306a36Sopenharmony_ci .probe = sca3300_probe, 69562306a36Sopenharmony_ci .id_table = sca3300_ids, 69662306a36Sopenharmony_ci}; 69762306a36Sopenharmony_cimodule_spi_driver(sca3300_driver); 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ciMODULE_AUTHOR("Tomas Melin <tomas.melin@vaisala.com>"); 70062306a36Sopenharmony_ciMODULE_DESCRIPTION("Murata SCA3300 SPI Accelerometer"); 70162306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 702