18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * SPI IIO driver for Bosch BMA400 triaxial acceleration sensor. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright 2020 Dan Robertson <dan@dlrobertson.com> 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci#include <linux/bits.h> 98c2ecf20Sopenharmony_ci#include <linux/init.h> 108c2ecf20Sopenharmony_ci#include <linux/mod_devicetable.h> 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci#include <linux/regmap.h> 138c2ecf20Sopenharmony_ci#include <linux/spi/spi.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include "bma400.h" 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#define BMA400_MAX_SPI_READ 2 188c2ecf20Sopenharmony_ci#define BMA400_SPI_READ_BUFFER_SIZE (BMA400_MAX_SPI_READ + 1) 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_cistatic int bma400_regmap_spi_read(void *context, 218c2ecf20Sopenharmony_ci const void *reg, size_t reg_size, 228c2ecf20Sopenharmony_ci void *val, size_t val_size) 238c2ecf20Sopenharmony_ci{ 248c2ecf20Sopenharmony_ci struct device *dev = context; 258c2ecf20Sopenharmony_ci struct spi_device *spi = to_spi_device(dev); 268c2ecf20Sopenharmony_ci u8 result[BMA400_SPI_READ_BUFFER_SIZE]; 278c2ecf20Sopenharmony_ci ssize_t status; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci if (val_size > BMA400_MAX_SPI_READ) 308c2ecf20Sopenharmony_ci return -EINVAL; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci status = spi_write_then_read(spi, reg, 1, result, val_size + 1); 338c2ecf20Sopenharmony_ci if (status) 348c2ecf20Sopenharmony_ci return status; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci /* 378c2ecf20Sopenharmony_ci * From the BMA400 datasheet: 388c2ecf20Sopenharmony_ci * 398c2ecf20Sopenharmony_ci * > For a basic read operation two bytes have to be read and the first 408c2ecf20Sopenharmony_ci * > has to be dropped and the second byte must be interpreted. 418c2ecf20Sopenharmony_ci */ 428c2ecf20Sopenharmony_ci memcpy(val, result + 1, val_size); 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci return 0; 458c2ecf20Sopenharmony_ci} 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistatic int bma400_regmap_spi_write(void *context, const void *data, 488c2ecf20Sopenharmony_ci size_t count) 498c2ecf20Sopenharmony_ci{ 508c2ecf20Sopenharmony_ci struct device *dev = context; 518c2ecf20Sopenharmony_ci struct spi_device *spi = to_spi_device(dev); 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci return spi_write(spi, data, count); 548c2ecf20Sopenharmony_ci} 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic struct regmap_bus bma400_regmap_bus = { 578c2ecf20Sopenharmony_ci .read = bma400_regmap_spi_read, 588c2ecf20Sopenharmony_ci .write = bma400_regmap_spi_write, 598c2ecf20Sopenharmony_ci .read_flag_mask = BIT(7), 608c2ecf20Sopenharmony_ci .max_raw_read = BMA400_MAX_SPI_READ, 618c2ecf20Sopenharmony_ci}; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_cistatic int bma400_spi_probe(struct spi_device *spi) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci const struct spi_device_id *id = spi_get_device_id(spi); 668c2ecf20Sopenharmony_ci struct regmap *regmap; 678c2ecf20Sopenharmony_ci unsigned int val; 688c2ecf20Sopenharmony_ci int ret; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci regmap = devm_regmap_init(&spi->dev, &bma400_regmap_bus, 718c2ecf20Sopenharmony_ci &spi->dev, &bma400_regmap_config); 728c2ecf20Sopenharmony_ci if (IS_ERR(regmap)) { 738c2ecf20Sopenharmony_ci dev_err(&spi->dev, "failed to create regmap\n"); 748c2ecf20Sopenharmony_ci return PTR_ERR(regmap); 758c2ecf20Sopenharmony_ci } 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci /* 788c2ecf20Sopenharmony_ci * Per the bma400 datasheet, the first SPI read may 798c2ecf20Sopenharmony_ci * return garbage. As the datasheet recommends, the 808c2ecf20Sopenharmony_ci * chip ID register will be read here and checked 818c2ecf20Sopenharmony_ci * again in the following probe. 828c2ecf20Sopenharmony_ci */ 838c2ecf20Sopenharmony_ci ret = regmap_read(regmap, BMA400_CHIP_ID_REG, &val); 848c2ecf20Sopenharmony_ci if (ret) 858c2ecf20Sopenharmony_ci dev_err(&spi->dev, "Failed to read chip id register\n"); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci return bma400_probe(&spi->dev, regmap, id->name); 888c2ecf20Sopenharmony_ci} 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cistatic int bma400_spi_remove(struct spi_device *spi) 918c2ecf20Sopenharmony_ci{ 928c2ecf20Sopenharmony_ci return bma400_remove(&spi->dev); 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistatic const struct spi_device_id bma400_spi_ids[] = { 968c2ecf20Sopenharmony_ci { "bma400", 0 }, 978c2ecf20Sopenharmony_ci { } 988c2ecf20Sopenharmony_ci}; 998c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(spi, bma400_spi_ids); 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistatic const struct of_device_id bma400_of_spi_match[] = { 1028c2ecf20Sopenharmony_ci { .compatible = "bosch,bma400" }, 1038c2ecf20Sopenharmony_ci { } 1048c2ecf20Sopenharmony_ci}; 1058c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, bma400_of_spi_match); 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_cistatic struct spi_driver bma400_spi_driver = { 1088c2ecf20Sopenharmony_ci .driver = { 1098c2ecf20Sopenharmony_ci .name = "bma400", 1108c2ecf20Sopenharmony_ci .of_match_table = bma400_of_spi_match, 1118c2ecf20Sopenharmony_ci }, 1128c2ecf20Sopenharmony_ci .probe = bma400_spi_probe, 1138c2ecf20Sopenharmony_ci .remove = bma400_spi_remove, 1148c2ecf20Sopenharmony_ci .id_table = bma400_spi_ids, 1158c2ecf20Sopenharmony_ci}; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_cimodule_spi_driver(bma400_spi_driver); 1188c2ecf20Sopenharmony_ciMODULE_AUTHOR("Dan Robertson <dan@dlrobertson.com>"); 1198c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Bosch BMA400 triaxial acceleration sensor (SPI)"); 1208c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 121