11b3bd859SHimanshu Jha // SPDX-License-Identifier: GPL-2.0
21b3bd859SHimanshu Jha /*
31b3bd859SHimanshu Jha * BME680 - SPI Driver
41b3bd859SHimanshu Jha *
51b3bd859SHimanshu Jha * Copyright (C) 2018 Himanshu Jha <himanshujha199640@gmail.com>
61b3bd859SHimanshu Jha */
7200da7efSAndy Shevchenko #include <linux/mod_devicetable.h>
81b3bd859SHimanshu Jha #include <linux/module.h>
91b3bd859SHimanshu Jha #include <linux/regmap.h>
101b3bd859SHimanshu Jha #include <linux/spi/spi.h>
111b3bd859SHimanshu Jha
121b3bd859SHimanshu Jha #include "bme680.h"
131b3bd859SHimanshu Jha
1473f3bc6dSMike Looijmans struct bme680_spi_bus_context {
1573f3bc6dSMike Looijmans struct spi_device *spi;
1673f3bc6dSMike Looijmans u8 current_page;
1773f3bc6dSMike Looijmans };
1873f3bc6dSMike Looijmans
1973f3bc6dSMike Looijmans /*
2073f3bc6dSMike Looijmans * In SPI mode there are only 7 address bits, a "page" register determines
2173f3bc6dSMike Looijmans * which part of the 8-bit range is active. This function looks at the address
2273f3bc6dSMike Looijmans * and writes the page selection bit if needed
2373f3bc6dSMike Looijmans */
bme680_regmap_spi_select_page(struct bme680_spi_bus_context * ctx,u8 reg)2473f3bc6dSMike Looijmans static int bme680_regmap_spi_select_page(
2573f3bc6dSMike Looijmans struct bme680_spi_bus_context *ctx, u8 reg)
2673f3bc6dSMike Looijmans {
2773f3bc6dSMike Looijmans struct spi_device *spi = ctx->spi;
2873f3bc6dSMike Looijmans int ret;
2973f3bc6dSMike Looijmans u8 buf[2];
3073f3bc6dSMike Looijmans u8 page = (reg & 0x80) ? 0 : 1; /* Page "1" is low range */
3173f3bc6dSMike Looijmans
3273f3bc6dSMike Looijmans if (page == ctx->current_page)
3373f3bc6dSMike Looijmans return 0;
3473f3bc6dSMike Looijmans
3573f3bc6dSMike Looijmans /*
3673f3bc6dSMike Looijmans * Data sheet claims we're only allowed to change bit 4, so we must do
3773f3bc6dSMike Looijmans * a read-modify-write on each and every page select
3873f3bc6dSMike Looijmans */
3973f3bc6dSMike Looijmans buf[0] = BME680_REG_STATUS;
4073f3bc6dSMike Looijmans ret = spi_write_then_read(spi, buf, 1, buf + 1, 1);
4173f3bc6dSMike Looijmans if (ret < 0) {
4273f3bc6dSMike Looijmans dev_err(&spi->dev, "failed to set page %u\n", page);
4373f3bc6dSMike Looijmans return ret;
4473f3bc6dSMike Looijmans }
4573f3bc6dSMike Looijmans
4673f3bc6dSMike Looijmans buf[0] = BME680_REG_STATUS;
4773f3bc6dSMike Looijmans if (page)
4873f3bc6dSMike Looijmans buf[1] |= BME680_SPI_MEM_PAGE_BIT;
4973f3bc6dSMike Looijmans else
5073f3bc6dSMike Looijmans buf[1] &= ~BME680_SPI_MEM_PAGE_BIT;
5173f3bc6dSMike Looijmans
5273f3bc6dSMike Looijmans ret = spi_write(spi, buf, 2);
5373f3bc6dSMike Looijmans if (ret < 0) {
5473f3bc6dSMike Looijmans dev_err(&spi->dev, "failed to set page %u\n", page);
5573f3bc6dSMike Looijmans return ret;
5673f3bc6dSMike Looijmans }
5773f3bc6dSMike Looijmans
5873f3bc6dSMike Looijmans ctx->current_page = page;
5973f3bc6dSMike Looijmans
6073f3bc6dSMike Looijmans return 0;
6173f3bc6dSMike Looijmans }
6273f3bc6dSMike Looijmans
bme680_regmap_spi_write(void * context,const void * data,size_t count)631b3bd859SHimanshu Jha static int bme680_regmap_spi_write(void *context, const void *data,
641b3bd859SHimanshu Jha size_t count)
651b3bd859SHimanshu Jha {
6673f3bc6dSMike Looijmans struct bme680_spi_bus_context *ctx = context;
6773f3bc6dSMike Looijmans struct spi_device *spi = ctx->spi;
6873f3bc6dSMike Looijmans int ret;
691b3bd859SHimanshu Jha u8 buf[2];
701b3bd859SHimanshu Jha
711b3bd859SHimanshu Jha memcpy(buf, data, 2);
7273f3bc6dSMike Looijmans
7373f3bc6dSMike Looijmans ret = bme680_regmap_spi_select_page(ctx, buf[0]);
7473f3bc6dSMike Looijmans if (ret)
7573f3bc6dSMike Looijmans return ret;
7673f3bc6dSMike Looijmans
771b3bd859SHimanshu Jha /*
781b3bd859SHimanshu Jha * The SPI register address (= full register address without bit 7)
791b3bd859SHimanshu Jha * and the write command (bit7 = RW = '0')
801b3bd859SHimanshu Jha */
811b3bd859SHimanshu Jha buf[0] &= ~0x80;
821b3bd859SHimanshu Jha
8373f3bc6dSMike Looijmans return spi_write(spi, buf, 2);
841b3bd859SHimanshu Jha }
851b3bd859SHimanshu Jha
bme680_regmap_spi_read(void * context,const void * reg,size_t reg_size,void * val,size_t val_size)861b3bd859SHimanshu Jha static int bme680_regmap_spi_read(void *context, const void *reg,
871b3bd859SHimanshu Jha size_t reg_size, void *val, size_t val_size)
881b3bd859SHimanshu Jha {
8973f3bc6dSMike Looijmans struct bme680_spi_bus_context *ctx = context;
9073f3bc6dSMike Looijmans struct spi_device *spi = ctx->spi;
9173f3bc6dSMike Looijmans int ret;
9273f3bc6dSMike Looijmans u8 addr = *(const u8 *)reg;
931b3bd859SHimanshu Jha
9473f3bc6dSMike Looijmans ret = bme680_regmap_spi_select_page(ctx, addr);
9573f3bc6dSMike Looijmans if (ret)
9673f3bc6dSMike Looijmans return ret;
9773f3bc6dSMike Looijmans
9873f3bc6dSMike Looijmans addr |= 0x80; /* bit7 = RW = '1' */
9973f3bc6dSMike Looijmans
10073f3bc6dSMike Looijmans return spi_write_then_read(spi, &addr, 1, val, val_size);
1011b3bd859SHimanshu Jha }
1021b3bd859SHimanshu Jha
103*297fef49SJavier Carrasco static const struct regmap_bus bme680_regmap_bus = {
1041b3bd859SHimanshu Jha .write = bme680_regmap_spi_write,
1051b3bd859SHimanshu Jha .read = bme680_regmap_spi_read,
1061b3bd859SHimanshu Jha .reg_format_endian_default = REGMAP_ENDIAN_BIG,
1071b3bd859SHimanshu Jha .val_format_endian_default = REGMAP_ENDIAN_BIG,
1081b3bd859SHimanshu Jha };
1091b3bd859SHimanshu Jha
bme680_spi_probe(struct spi_device * spi)1101b3bd859SHimanshu Jha static int bme680_spi_probe(struct spi_device *spi)
1111b3bd859SHimanshu Jha {
1121b3bd859SHimanshu Jha const struct spi_device_id *id = spi_get_device_id(spi);
11373f3bc6dSMike Looijmans struct bme680_spi_bus_context *bus_context;
1141b3bd859SHimanshu Jha struct regmap *regmap;
1151b3bd859SHimanshu Jha int ret;
1161b3bd859SHimanshu Jha
1171b3bd859SHimanshu Jha spi->bits_per_word = 8;
1181b3bd859SHimanshu Jha ret = spi_setup(spi);
1191b3bd859SHimanshu Jha if (ret < 0) {
1201b3bd859SHimanshu Jha dev_err(&spi->dev, "spi_setup failed!\n");
1211b3bd859SHimanshu Jha return ret;
1221b3bd859SHimanshu Jha }
1231b3bd859SHimanshu Jha
12473f3bc6dSMike Looijmans bus_context = devm_kzalloc(&spi->dev, sizeof(*bus_context), GFP_KERNEL);
12573f3bc6dSMike Looijmans if (!bus_context)
12673f3bc6dSMike Looijmans return -ENOMEM;
12773f3bc6dSMike Looijmans
12873f3bc6dSMike Looijmans bus_context->spi = spi;
12973f3bc6dSMike Looijmans bus_context->current_page = 0xff; /* Undefined on warm boot */
13073f3bc6dSMike Looijmans
1311b3bd859SHimanshu Jha regmap = devm_regmap_init(&spi->dev, &bme680_regmap_bus,
13273f3bc6dSMike Looijmans bus_context, &bme680_regmap_config);
1331b3bd859SHimanshu Jha if (IS_ERR(regmap)) {
134d612eb13SAndy Shevchenko dev_err(&spi->dev, "Failed to register spi regmap %ld\n", PTR_ERR(regmap));
1351b3bd859SHimanshu Jha return PTR_ERR(regmap);
1361b3bd859SHimanshu Jha }
1371b3bd859SHimanshu Jha
1381b3bd859SHimanshu Jha return bme680_core_probe(&spi->dev, regmap, id->name);
1391b3bd859SHimanshu Jha }
1401b3bd859SHimanshu Jha
1411b3bd859SHimanshu Jha static const struct spi_device_id bme680_spi_id[] = {
1421b3bd859SHimanshu Jha {"bme680", 0},
1431b3bd859SHimanshu Jha {},
1441b3bd859SHimanshu Jha };
1451b3bd859SHimanshu Jha MODULE_DEVICE_TABLE(spi, bme680_spi_id);
1461b3bd859SHimanshu Jha
147f7da8845SSebastien Bourdelin static const struct of_device_id bme680_of_spi_match[] = {
148f7da8845SSebastien Bourdelin { .compatible = "bosch,bme680", },
149f7da8845SSebastien Bourdelin {},
150f7da8845SSebastien Bourdelin };
151f7da8845SSebastien Bourdelin MODULE_DEVICE_TABLE(of, bme680_of_spi_match);
152f7da8845SSebastien Bourdelin
1531b3bd859SHimanshu Jha static struct spi_driver bme680_spi_driver = {
1541b3bd859SHimanshu Jha .driver = {
1551b3bd859SHimanshu Jha .name = "bme680_spi",
156f7da8845SSebastien Bourdelin .of_match_table = bme680_of_spi_match,
1571b3bd859SHimanshu Jha },
1581b3bd859SHimanshu Jha .probe = bme680_spi_probe,
1591b3bd859SHimanshu Jha .id_table = bme680_spi_id,
1601b3bd859SHimanshu Jha };
1611b3bd859SHimanshu Jha module_spi_driver(bme680_spi_driver);
1621b3bd859SHimanshu Jha
1631b3bd859SHimanshu Jha MODULE_AUTHOR("Himanshu Jha <himanshujha199640@gmail.com>");
1641b3bd859SHimanshu Jha MODULE_DESCRIPTION("Bosch BME680 SPI driver");
1651b3bd859SHimanshu Jha MODULE_LICENSE("GPL v2");
166146b43d9SJonathan Cameron MODULE_IMPORT_NS(IIO_BME680);
167