File Index
Files and directories
Sign in
FILE

bme680_spi.c

File preview with syntax highlighting.

linux-6.19.14/drivers/iio/chemical/bme680_spi.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * BME680 - SPI Driver
  4 *
  5 * Copyright (C) 2018 Himanshu Jha <himanshujha199640@gmail.com>
  6 */
  7#include <linux/mod_devicetable.h>
  8#include <linux/module.h>
  9#include <linux/regmap.h>
 10#include <linux/spi/spi.h>
 11
 12#include "bme680.h"
 13
 14struct bme680_spi_bus_context {
 15	struct spi_device *spi;
 16	u8 current_page;
 17};
 18
 19/*
 20 * In SPI mode there are only 7 address bits, a "page" register determines
 21 * which part of the 8-bit range is active. This function looks at the address
 22 * and writes the page selection bit if needed
 23 */
 24static int bme680_regmap_spi_select_page(
 25	struct bme680_spi_bus_context *ctx, u8 reg)
 26{
 27	struct spi_device *spi = ctx->spi;
 28	int ret;
 29	u8 buf[2];
 30	u8 page = (reg & 0x80) ? 0 : 1; /* Page "1" is low range */
 31
 32	if (page == ctx->current_page)
 33		return 0;
 34
 35	/*
 36	 * Data sheet claims we're only allowed to change bit 4, so we must do
 37	 * a read-modify-write on each and every page select
 38	 */
 39	buf[0] = BME680_REG_STATUS;
 40	ret = spi_write_then_read(spi, buf, 1, buf + 1, 1);
 41	if (ret < 0) {
 42		dev_err(&spi->dev, "failed to set page %u\n", page);
 43		return ret;
 44	}
 45
 46	buf[0] = BME680_REG_STATUS;
 47	if (page)
 48		buf[1] |= BME680_SPI_MEM_PAGE_BIT;
 49	else
 50		buf[1] &= ~BME680_SPI_MEM_PAGE_BIT;
 51
 52	ret = spi_write(spi, buf, 2);
 53	if (ret < 0) {
 54		dev_err(&spi->dev, "failed to set page %u\n", page);
 55		return ret;
 56	}
 57
 58	ctx->current_page = page;
 59
 60	return 0;
 61}
 62
 63static int bme680_regmap_spi_write(void *context, const void *data,
 64				   size_t count)
 65{
 66	struct bme680_spi_bus_context *ctx = context;
 67	struct spi_device *spi = ctx->spi;
 68	int ret;
 69	u8 buf[2];
 70
 71	memcpy(buf, data, 2);
 72
 73	ret = bme680_regmap_spi_select_page(ctx, buf[0]);
 74	if (ret)
 75		return ret;
 76
 77	/*
 78	 * The SPI register address (= full register address without bit 7)
 79	 * and the write command (bit7 = RW = '0')
 80	 */
 81	buf[0] &= ~0x80;
 82
 83	return spi_write(spi, buf, 2);
 84}
 85
 86static int bme680_regmap_spi_read(void *context, const void *reg,
 87				  size_t reg_size, void *val, size_t val_size)
 88{
 89	struct bme680_spi_bus_context *ctx = context;
 90	struct spi_device *spi = ctx->spi;
 91	int ret;
 92	u8 addr = *(const u8 *)reg;
 93
 94	ret = bme680_regmap_spi_select_page(ctx, addr);
 95	if (ret)
 96		return ret;
 97
 98	addr |= 0x80; /* bit7 = RW = '1' */
 99
100	return spi_write_then_read(spi, &addr, 1, val, val_size);
101}
102
103static const struct regmap_bus bme680_regmap_bus = {
104	.write = bme680_regmap_spi_write,
105	.read = bme680_regmap_spi_read,
106	.reg_format_endian_default = REGMAP_ENDIAN_BIG,
107	.val_format_endian_default = REGMAP_ENDIAN_BIG,
108};
109
110static int bme680_spi_probe(struct spi_device *spi)
111{
112	const struct spi_device_id *id = spi_get_device_id(spi);
113	struct bme680_spi_bus_context *bus_context;
114	struct regmap *regmap;
115
116	bus_context = devm_kzalloc(&spi->dev, sizeof(*bus_context), GFP_KERNEL);
117	if (!bus_context)
118		return -ENOMEM;
119
120	bus_context->spi = spi;
121	bus_context->current_page = 0xff; /* Undefined on warm boot */
122
123	regmap = devm_regmap_init(&spi->dev, &bme680_regmap_bus,
124				  bus_context, &bme680_regmap_config);
125	if (IS_ERR(regmap)) {
126		dev_err(&spi->dev, "Failed to register spi regmap %ld\n", PTR_ERR(regmap));
127		return PTR_ERR(regmap);
128	}
129
130	return bme680_core_probe(&spi->dev, regmap, id->name);
131}
132
133static const struct spi_device_id bme680_spi_id[] = {
134	{"bme680", 0},
135	{ }
136};
137MODULE_DEVICE_TABLE(spi, bme680_spi_id);
138
139static const struct of_device_id bme680_of_spi_match[] = {
140	{ .compatible = "bosch,bme680", },
141	{ }
142};
143MODULE_DEVICE_TABLE(of, bme680_of_spi_match);
144
145static struct spi_driver bme680_spi_driver = {
146	.driver = {
147		.name			= "bme680_spi",
148		.of_match_table		= bme680_of_spi_match,
149		.pm = pm_ptr(&bme680_dev_pm_ops),
150	},
151	.probe = bme680_spi_probe,
152	.id_table = bme680_spi_id,
153};
154module_spi_driver(bme680_spi_driver);
155
156MODULE_AUTHOR("Himanshu Jha <himanshujha199640@gmail.com>");
157MODULE_DESCRIPTION("Bosch BME680 SPI driver");
158MODULE_LICENSE("GPL v2");
159MODULE_IMPORT_NS("IIO_BME680");
~/ Read-only file preview.