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