1 /*
2  * Copyright (c) 2016, 2017 Intel Corporation
3  * Copyright (c) 2017 IpTronix S.r.l.
4  * Copyright (c) 2021 Nordic Semiconductor ASA
5  * Copyright (c) 2022, Leonard Pollak
6  *
7  * SPDX-License-Identifier: Apache-2.0
8  */
9 
10 /*
11  * Bus-specific functionality for BME680s accessed via SPI.
12  */
13 
14 #include <zephyr/logging/log.h>
15 #include "bme680.h"
16 
17 #if BME680_BUS_SPI
18 
19 LOG_MODULE_DECLARE(bme680, CONFIG_SENSOR_LOG_LEVEL);
20 
bme680_bus_check_spi(const union bme680_bus * bus)21 static int bme680_bus_check_spi(const union bme680_bus *bus)
22 {
23 	return spi_is_ready_dt(&bus->spi) ? 0 : -ENODEV;
24 }
25 
bme680_set_mem_page(const struct device * dev,uint8_t addr)26 static inline int bme680_set_mem_page(const struct device *dev, uint8_t addr)
27 {
28 	const struct bme680_config *config = dev->config;
29 	struct bme680_data *data = dev->data;
30 	uint8_t page = (addr > 0x7f) ? 0U : 1U;
31 	int err = 0;
32 
33 	if (data->mem_page != page) {
34 		uint8_t buf[2];
35 
36 		struct spi_buf tx_buf = {
37 			.buf = &buf[0],
38 			.len = 1,
39 		};
40 		const struct spi_buf_set tx = {
41 			.buffers = &tx_buf,
42 			.count = 1,
43 		};
44 
45 		const struct spi_buf rx_buf[] = {
46 			{ .buf = NULL, .len = 1 },
47 			{ .buf = &buf[1], .len = 1 },
48 		};
49 		const struct spi_buf_set rx = {
50 			.buffers = rx_buf,
51 			.count = ARRAY_SIZE(rx_buf),
52 		};
53 
54 		buf[0] = BME680_REG_STATUS | BME680_SPI_READ_BIT;
55 		err = spi_transceive_dt(&config->bus.spi, &tx, &rx);
56 		if (err < 0) {
57 			return err;
58 		}
59 
60 		if (data->mem_page == 1U) {
61 			buf[1] &= ~BME680_SPI_MEM_PAGE_MSK;
62 		} else {
63 			buf[1] |= BME680_SPI_MEM_PAGE_MSK;
64 		}
65 
66 		buf[0] = BME680_REG_STATUS & BME680_SPI_WRITE_MSK;
67 		tx_buf.len = 2;
68 		err = spi_write_dt(&config->bus.spi, &tx);
69 		if (err < 0) {
70 			return err;
71 		}
72 
73 		data->mem_page = page;
74 	}
75 
76 	return err;
77 }
78 
bme680_reg_write_spi(const struct device * dev,uint8_t reg,uint8_t val)79 static int bme680_reg_write_spi(const struct device *dev,
80 				uint8_t reg, uint8_t val)
81 {
82 	const struct bme680_config *config = dev->config;
83 	int err;
84 	uint8_t cmd[] = { reg & BME680_SPI_WRITE_MSK, val };
85 	const struct spi_buf tx_buf = {
86 		.buf = cmd,
87 		.len = sizeof(cmd)
88 	};
89 	const struct spi_buf_set tx = {
90 		.buffers = &tx_buf,
91 		.count = 1
92 	};
93 
94 	err = bme680_set_mem_page(dev, reg);
95 	if (err) {
96 		return err;
97 	}
98 
99 	err = spi_write_dt(&config->bus.spi, &tx);
100 
101 	return err;
102 }
103 
bme680_reg_read_spi(const struct device * dev,uint8_t start,uint8_t * buf,int size)104 static int bme680_reg_read_spi(const struct device *dev,
105 			       uint8_t start, uint8_t *buf, int size)
106 {
107 	const struct bme680_config *config = dev->config;
108 	int err;
109 	uint8_t addr;
110 	const struct spi_buf tx_buf = {
111 		.buf = &addr,
112 		.len = 1
113 	};
114 	const struct spi_buf_set tx = {
115 		.buffers = &tx_buf,
116 		.count = 1
117 	};
118 	struct spi_buf rx_buf[2];
119 	const struct spi_buf_set rx = {
120 		.buffers = rx_buf,
121 		.count = ARRAY_SIZE(rx_buf)
122 	};
123 
124 	rx_buf[0].buf = NULL;
125 	rx_buf[0].len = 1;
126 
127 	addr = start | BME680_SPI_READ_BIT;
128 	rx_buf[1].buf = buf;
129 	rx_buf[1].len = size;
130 
131 	err = bme680_set_mem_page(dev, start);
132 	if (err) {
133 		return err;
134 	}
135 
136 	err = spi_transceive_dt(&config->bus.spi, &tx, &rx);
137 
138 	return err;
139 }
140 
141 const struct bme680_bus_io bme680_bus_io_spi = {
142 	.check = bme680_bus_check_spi,
143 	.read = bme680_reg_read_spi,
144 	.write = bme680_reg_write_spi,
145 };
146 #endif /* BME680_BUS_SPI */
147