1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* |
3 | * Copyright (C) 2021 Analog Devices, Inc. |
4 | * Author: Cosmin Tanislav <cosmin.tanislav@analog.com> |
5 | */ |
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 <linux/iio/iio.h> |
13 | |
14 | #include "adxl367.h" |
15 | |
16 | #define ADXL367_SPI_WRITE_COMMAND 0x0A |
17 | #define ADXL367_SPI_READ_COMMAND 0x0B |
18 | #define ADXL367_SPI_FIFO_COMMAND 0x0D |
19 | |
20 | struct adxl367_spi_state { |
21 | struct spi_device *spi; |
22 | |
23 | struct spi_message reg_write_msg; |
24 | struct spi_transfer reg_write_xfer[2]; |
25 | |
26 | struct spi_message reg_read_msg; |
27 | struct spi_transfer reg_read_xfer[2]; |
28 | |
29 | struct spi_message fifo_msg; |
30 | struct spi_transfer fifo_xfer[2]; |
31 | |
32 | /* |
33 | * DMA (thus cache coherency maintenance) may require the |
34 | * transfer buffers live in their own cache lines. |
35 | */ |
36 | u8 reg_write_tx_buf[1] __aligned(IIO_DMA_MINALIGN); |
37 | u8 reg_read_tx_buf[2]; |
38 | u8 fifo_tx_buf[1]; |
39 | }; |
40 | |
41 | static int adxl367_read_fifo(void *context, __be16 *fifo_buf, |
42 | unsigned int fifo_entries) |
43 | { |
44 | struct adxl367_spi_state *st = context; |
45 | |
46 | st->fifo_xfer[1].rx_buf = fifo_buf; |
47 | st->fifo_xfer[1].len = fifo_entries * sizeof(*fifo_buf); |
48 | |
49 | return spi_sync(spi: st->spi, message: &st->fifo_msg); |
50 | } |
51 | |
52 | static int adxl367_read(void *context, const void *reg_buf, size_t reg_size, |
53 | void *val_buf, size_t val_size) |
54 | { |
55 | struct adxl367_spi_state *st = context; |
56 | u8 reg = ((const u8 *)reg_buf)[0]; |
57 | |
58 | st->reg_read_tx_buf[1] = reg; |
59 | st->reg_read_xfer[1].rx_buf = val_buf; |
60 | st->reg_read_xfer[1].len = val_size; |
61 | |
62 | return spi_sync(spi: st->spi, message: &st->reg_read_msg); |
63 | } |
64 | |
65 | static int adxl367_write(void *context, const void *val_buf, size_t val_size) |
66 | { |
67 | struct adxl367_spi_state *st = context; |
68 | |
69 | st->reg_write_xfer[1].tx_buf = val_buf; |
70 | st->reg_write_xfer[1].len = val_size; |
71 | |
72 | return spi_sync(spi: st->spi, message: &st->reg_write_msg); |
73 | } |
74 | |
75 | static struct regmap_bus adxl367_spi_regmap_bus = { |
76 | .read = adxl367_read, |
77 | .write = adxl367_write, |
78 | }; |
79 | |
80 | static const struct regmap_config adxl367_spi_regmap_config = { |
81 | .reg_bits = 8, |
82 | .val_bits = 8, |
83 | }; |
84 | |
85 | static const struct adxl367_ops adxl367_spi_ops = { |
86 | .read_fifo = adxl367_read_fifo, |
87 | }; |
88 | |
89 | static int adxl367_spi_probe(struct spi_device *spi) |
90 | { |
91 | struct adxl367_spi_state *st; |
92 | struct regmap *regmap; |
93 | |
94 | st = devm_kzalloc(dev: &spi->dev, size: sizeof(*st), GFP_KERNEL); |
95 | if (!st) |
96 | return -ENOMEM; |
97 | |
98 | st->spi = spi; |
99 | |
100 | /* |
101 | * Xfer: [XFR1] [ XFR2 ] |
102 | * Master: 0x0A ADDR DATA0 DATA1 ... DATAN |
103 | * Slave: .... .......................... |
104 | */ |
105 | st->reg_write_tx_buf[0] = ADXL367_SPI_WRITE_COMMAND; |
106 | st->reg_write_xfer[0].tx_buf = st->reg_write_tx_buf; |
107 | st->reg_write_xfer[0].len = sizeof(st->reg_write_tx_buf); |
108 | spi_message_init_with_transfers(m: &st->reg_write_msg, |
109 | xfers: st->reg_write_xfer, num_xfers: 2); |
110 | |
111 | /* |
112 | * Xfer: [ XFR1 ] [ XFR2 ] |
113 | * Master: 0x0B ADDR ..................... |
114 | * Slave: ......... DATA0 DATA1 ... DATAN |
115 | */ |
116 | st->reg_read_tx_buf[0] = ADXL367_SPI_READ_COMMAND; |
117 | st->reg_read_xfer[0].tx_buf = st->reg_read_tx_buf; |
118 | st->reg_read_xfer[0].len = sizeof(st->reg_read_tx_buf); |
119 | spi_message_init_with_transfers(m: &st->reg_read_msg, |
120 | xfers: st->reg_read_xfer, num_xfers: 2); |
121 | |
122 | /* |
123 | * Xfer: [XFR1] [ XFR2 ] |
124 | * Master: 0x0D ..................... |
125 | * Slave: .... DATA0 DATA1 ... DATAN |
126 | */ |
127 | st->fifo_tx_buf[0] = ADXL367_SPI_FIFO_COMMAND; |
128 | st->fifo_xfer[0].tx_buf = st->fifo_tx_buf; |
129 | st->fifo_xfer[0].len = sizeof(st->fifo_tx_buf); |
130 | spi_message_init_with_transfers(m: &st->fifo_msg, xfers: st->fifo_xfer, num_xfers: 2); |
131 | |
132 | regmap = devm_regmap_init(&spi->dev, &adxl367_spi_regmap_bus, st, |
133 | &adxl367_spi_regmap_config); |
134 | if (IS_ERR(ptr: regmap)) |
135 | return PTR_ERR(ptr: regmap); |
136 | |
137 | return adxl367_probe(dev: &spi->dev, ops: &adxl367_spi_ops, context: st, regmap, irq: spi->irq); |
138 | } |
139 | |
140 | static const struct spi_device_id adxl367_spi_id[] = { |
141 | { "adxl367" , 0 }, |
142 | { }, |
143 | }; |
144 | MODULE_DEVICE_TABLE(spi, adxl367_spi_id); |
145 | |
146 | static const struct of_device_id adxl367_of_match[] = { |
147 | { .compatible = "adi,adxl367" }, |
148 | { }, |
149 | }; |
150 | MODULE_DEVICE_TABLE(of, adxl367_of_match); |
151 | |
152 | static struct spi_driver adxl367_spi_driver = { |
153 | .driver = { |
154 | .name = "adxl367_spi" , |
155 | .of_match_table = adxl367_of_match, |
156 | }, |
157 | .probe = adxl367_spi_probe, |
158 | .id_table = adxl367_spi_id, |
159 | }; |
160 | |
161 | module_spi_driver(adxl367_spi_driver); |
162 | |
163 | MODULE_IMPORT_NS(IIO_ADXL367); |
164 | MODULE_AUTHOR("Cosmin Tanislav <cosmin.tanislav@analog.com>" ); |
165 | MODULE_DESCRIPTION("Analog Devices ADXL367 3-axis accelerometer SPI driver" ); |
166 | MODULE_LICENSE("GPL" ); |
167 | |