1 /* ST Microelectronics LIS2DH 3-axis accelerometer driver
2  *
3  * Copyright (c) 2020 STMicroelectronics
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  *
7  * Datasheet:
8  * https://www.st.com/resource/en/datasheet/lis2dh.pdf
9  */
10 
11 #define DT_DRV_COMPAT st_lis2dh
12 
13 #include <string.h>
14 #include "lis2dh.h"
15 #include <zephyr/logging/log.h>
16 
17 #if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi)
18 
19 LOG_MODULE_DECLARE(lis2dh, CONFIG_SENSOR_LOG_LEVEL);
20 
21 
22 #define LIS2DH_SPI_READ_BIT		BIT(7)
23 #define LIS2DH_SPI_AUTOINC		BIT(6)
24 #define LIS2DH_SPI_ADDR_MASK		BIT_MASK(6)
25 
lis2dh_raw_read(const struct device * dev,uint8_t reg_addr,uint8_t * value,uint8_t len)26 static int lis2dh_raw_read(const struct device *dev, uint8_t reg_addr,
27 			    uint8_t *value, uint8_t len)
28 {
29 	const struct lis2dh_config *cfg = dev->config;
30 	uint8_t buffer_tx[2] = { reg_addr | LIS2DH_SPI_READ_BIT, 0 };
31 	const struct spi_buf tx_buf = {
32 			.buf = buffer_tx,
33 			.len = 2,
34 	};
35 	const struct spi_buf_set tx = {
36 		.buffers = &tx_buf,
37 		.count = 1
38 	};
39 	const struct spi_buf rx_buf[2] = {
40 		{
41 			.buf = NULL,
42 			.len = 1,
43 		},
44 		{
45 			.buf = value,
46 			.len = len,
47 		}
48 	};
49 	const struct spi_buf_set rx = {
50 		.buffers = rx_buf,
51 		.count = 2
52 	};
53 
54 
55 	if (len > 64) {
56 		return -EIO;
57 	}
58 
59 	if (len > 1) {
60 		buffer_tx[0] |= LIS2DH_SPI_AUTOINC;
61 	}
62 
63 	if (spi_transceive_dt(&cfg->bus_cfg.spi, &tx, &rx)) {
64 		return -EIO;
65 	}
66 
67 	return 0;
68 }
69 
lis2dh_raw_write(const struct device * dev,uint8_t reg_addr,uint8_t * value,uint8_t len)70 static int lis2dh_raw_write(const struct device *dev, uint8_t reg_addr,
71 			     uint8_t *value, uint8_t len)
72 {
73 	const struct lis2dh_config *cfg = dev->config;
74 	uint8_t buffer_tx[1] = { reg_addr & ~LIS2DH_SPI_READ_BIT };
75 	const struct spi_buf tx_buf[2] = {
76 		{
77 			.buf = buffer_tx,
78 			.len = 1,
79 		},
80 		{
81 			.buf = value,
82 			.len = len,
83 		}
84 	};
85 	const struct spi_buf_set tx = {
86 		.buffers = tx_buf,
87 		.count = 2
88 	};
89 
90 
91 	if (len > 64) {
92 		return -EIO;
93 	}
94 
95 	if (len > 1) {
96 		buffer_tx[0] |= LIS2DH_SPI_AUTOINC;
97 	}
98 
99 	if (spi_write_dt(&cfg->bus_cfg.spi, &tx)) {
100 		return -EIO;
101 	}
102 
103 	return 0;
104 }
105 
lis2dh_spi_read_data(const struct device * dev,uint8_t reg_addr,uint8_t * value,uint8_t len)106 static int lis2dh_spi_read_data(const struct device *dev, uint8_t reg_addr,
107 				 uint8_t *value, uint8_t len)
108 {
109 	return lis2dh_raw_read(dev, reg_addr, value, len);
110 }
111 
lis2dh_spi_write_data(const struct device * dev,uint8_t reg_addr,uint8_t * value,uint8_t len)112 static int lis2dh_spi_write_data(const struct device *dev, uint8_t reg_addr,
113 				  uint8_t *value, uint8_t len)
114 {
115 	return lis2dh_raw_write(dev, reg_addr, value, len);
116 }
117 
lis2dh_spi_read_reg(const struct device * dev,uint8_t reg_addr,uint8_t * value)118 static int lis2dh_spi_read_reg(const struct device *dev, uint8_t reg_addr,
119 				uint8_t *value)
120 {
121 	return lis2dh_raw_read(dev, reg_addr, value, 1);
122 }
123 
lis2dh_spi_write_reg(const struct device * dev,uint8_t reg_addr,uint8_t value)124 static int lis2dh_spi_write_reg(const struct device *dev, uint8_t reg_addr,
125 				uint8_t value)
126 {
127 	uint8_t tmp_val = value;
128 
129 	return lis2dh_raw_write(dev, reg_addr, &tmp_val, 1);
130 }
131 
lis2dh_spi_update_reg(const struct device * dev,uint8_t reg_addr,uint8_t mask,uint8_t value)132 static int lis2dh_spi_update_reg(const struct device *dev, uint8_t reg_addr,
133 				  uint8_t mask, uint8_t value)
134 {
135 	uint8_t tmp_val;
136 
137 	lis2dh_raw_read(dev, reg_addr, &tmp_val, 1);
138 	tmp_val = (tmp_val & ~mask) | (value & mask);
139 
140 	return lis2dh_raw_write(dev, reg_addr, &tmp_val, 1);
141 }
142 
143 static const struct lis2dh_transfer_function lis2dh_spi_transfer_fn = {
144 	.read_data = lis2dh_spi_read_data,
145 	.write_data = lis2dh_spi_write_data,
146 	.read_reg  = lis2dh_spi_read_reg,
147 	.write_reg  = lis2dh_spi_write_reg,
148 	.update_reg = lis2dh_spi_update_reg,
149 };
150 
lis2dh_spi_init(const struct device * dev)151 int lis2dh_spi_init(const struct device *dev)
152 {
153 	struct lis2dh_data *data = dev->data;
154 	const struct lis2dh_config *cfg = dev->config;
155 
156 	data->hw_tf = &lis2dh_spi_transfer_fn;
157 
158 	if (!spi_is_ready_dt(&cfg->bus_cfg.spi)) {
159 		LOG_ERR("SPI bus is not ready");
160 		return -ENODEV;
161 	}
162 
163 	return 0;
164 }
165 #endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) */
166