1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Analog Devices AD-FMCOMMS1-EBZ board I2C-SPI bridge driver
5 * Copyright 2012 Analog Devices Inc.
6 * Author: Lars-Peter Clausen <lars@metafoo.de>
9 #include <linux/kernel.h>
10 #include <linux/module.h>
11 #include <linux/delay.h>
12 #include <linux/i2c.h>
13 #include <linux/spi/spi.h>
14 #include <asm/unaligned.h>
16 #define SPI_XCOMM_SETTINGS_LEN_OFFSET 10
17 #define SPI_XCOMM_SETTINGS_3WIRE BIT(6)
18 #define SPI_XCOMM_SETTINGS_CS_HIGH BIT(5)
19 #define SPI_XCOMM_SETTINGS_SAMPLE_END BIT(4)
20 #define SPI_XCOMM_SETTINGS_CPHA BIT(3)
21 #define SPI_XCOMM_SETTINGS_CPOL BIT(2)
22 #define SPI_XCOMM_SETTINGS_CLOCK_DIV_MASK 0x3
23 #define SPI_XCOMM_SETTINGS_CLOCK_DIV_64 0x2
24 #define SPI_XCOMM_SETTINGS_CLOCK_DIV_16 0x1
25 #define SPI_XCOMM_SETTINGS_CLOCK_DIV_4 0x0
27 #define SPI_XCOMM_CMD_UPDATE_CONFIG 0x03
28 #define SPI_XCOMM_CMD_WRITE 0x04
30 #define SPI_XCOMM_CLOCK 48000000
33 struct i2c_client
*i2c
;
38 unsigned int current_speed
;
43 static int spi_xcomm_sync_config(struct spi_xcomm
*spi_xcomm
, unsigned int len
)
46 uint8_t *buf
= spi_xcomm
->buf
;
48 settings
= spi_xcomm
->settings
;
49 settings
|= len
<< SPI_XCOMM_SETTINGS_LEN_OFFSET
;
51 buf
[0] = SPI_XCOMM_CMD_UPDATE_CONFIG
;
52 put_unaligned_be16(settings
, &buf
[1]);
53 put_unaligned_be16(spi_xcomm
->chipselect
, &buf
[3]);
55 return i2c_master_send(spi_xcomm
->i2c
, buf
, 5);
58 static void spi_xcomm_chipselect(struct spi_xcomm
*spi_xcomm
,
59 struct spi_device
*spi
, int is_active
)
61 unsigned long cs
= spi
->chip_select
;
62 uint16_t chipselect
= spi_xcomm
->chipselect
;
65 chipselect
|= BIT(cs
);
67 chipselect
&= ~BIT(cs
);
69 spi_xcomm
->chipselect
= chipselect
;
72 static int spi_xcomm_setup_transfer(struct spi_xcomm
*spi_xcomm
,
73 struct spi_device
*spi
, struct spi_transfer
*t
, unsigned int *settings
)
78 if (t
->speed_hz
!= spi_xcomm
->current_speed
) {
81 divider
= DIV_ROUND_UP(SPI_XCOMM_CLOCK
, t
->speed_hz
);
83 *settings
|= SPI_XCOMM_SETTINGS_CLOCK_DIV_64
;
84 else if (divider
>= 16)
85 *settings
|= SPI_XCOMM_SETTINGS_CLOCK_DIV_16
;
87 *settings
|= SPI_XCOMM_SETTINGS_CLOCK_DIV_4
;
89 spi_xcomm
->current_speed
= t
->speed_hz
;
92 if (spi
->mode
& SPI_CPOL
)
93 *settings
|= SPI_XCOMM_SETTINGS_CPOL
;
95 *settings
&= ~SPI_XCOMM_SETTINGS_CPOL
;
97 if (spi
->mode
& SPI_CPHA
)
98 *settings
&= ~SPI_XCOMM_SETTINGS_CPHA
;
100 *settings
|= SPI_XCOMM_SETTINGS_CPHA
;
102 if (spi
->mode
& SPI_3WIRE
)
103 *settings
|= SPI_XCOMM_SETTINGS_3WIRE
;
105 *settings
&= ~SPI_XCOMM_SETTINGS_3WIRE
;
110 static int spi_xcomm_txrx_bufs(struct spi_xcomm
*spi_xcomm
,
111 struct spi_device
*spi
, struct spi_transfer
*t
)
116 spi_xcomm
->buf
[0] = SPI_XCOMM_CMD_WRITE
;
117 memcpy(spi_xcomm
->buf
+ 1, t
->tx_buf
, t
->len
);
119 ret
= i2c_master_send(spi_xcomm
->i2c
, spi_xcomm
->buf
, t
->len
+ 1);
122 else if (ret
!= t
->len
+ 1)
124 } else if (t
->rx_buf
) {
125 ret
= i2c_master_recv(spi_xcomm
->i2c
, t
->rx_buf
, t
->len
);
128 else if (ret
!= t
->len
)
135 static int spi_xcomm_transfer_one(struct spi_master
*master
,
136 struct spi_message
*msg
)
138 struct spi_xcomm
*spi_xcomm
= spi_master_get_devdata(master
);
139 unsigned int settings
= spi_xcomm
->settings
;
140 struct spi_device
*spi
= msg
->spi
;
141 unsigned cs_change
= 0;
142 struct spi_transfer
*t
;
143 bool is_first
= true;
147 spi_xcomm_chipselect(spi_xcomm
, spi
, true);
149 list_for_each_entry(t
, &msg
->transfers
, transfer_list
) {
151 if (!t
->tx_buf
&& !t
->rx_buf
&& t
->len
) {
156 status
= spi_xcomm_setup_transfer(spi_xcomm
, spi
, t
, &settings
);
160 is_last
= list_is_last(&t
->transfer_list
, &msg
->transfers
);
161 cs_change
= t
->cs_change
;
163 if (cs_change
^ is_last
)
169 spi_xcomm
->settings
= settings
;
170 status
= spi_xcomm_sync_config(spi_xcomm
, t
->len
);
173 } else if (settings
!= spi_xcomm
->settings
|| is_first
) {
174 spi_xcomm
->settings
= settings
;
175 status
= spi_xcomm_sync_config(spi_xcomm
, 0);
181 status
= spi_xcomm_txrx_bufs(spi_xcomm
, spi
, t
);
187 msg
->actual_length
+= status
;
192 udelay(t
->delay_usecs
);
197 if (status
!= 0 || !cs_change
)
198 spi_xcomm_chipselect(spi_xcomm
, spi
, false);
200 msg
->status
= status
;
201 spi_finalize_current_message(master
);
206 static int spi_xcomm_probe(struct i2c_client
*i2c
,
207 const struct i2c_device_id
*id
)
209 struct spi_xcomm
*spi_xcomm
;
210 struct spi_master
*master
;
213 master
= spi_alloc_master(&i2c
->dev
, sizeof(*spi_xcomm
));
217 spi_xcomm
= spi_master_get_devdata(master
);
218 spi_xcomm
->i2c
= i2c
;
220 master
->num_chipselect
= 16;
221 master
->mode_bits
= SPI_CPHA
| SPI_CPOL
| SPI_3WIRE
;
222 master
->bits_per_word_mask
= SPI_BPW_MASK(8);
223 master
->flags
= SPI_MASTER_HALF_DUPLEX
;
224 master
->transfer_one_message
= spi_xcomm_transfer_one
;
225 master
->dev
.of_node
= i2c
->dev
.of_node
;
226 i2c_set_clientdata(i2c
, master
);
228 ret
= devm_spi_register_master(&i2c
->dev
, master
);
230 spi_master_put(master
);
235 static const struct i2c_device_id spi_xcomm_ids
[] = {
239 MODULE_DEVICE_TABLE(i2c
, spi_xcomm_ids
);
241 static struct i2c_driver spi_xcomm_driver
= {
245 .id_table
= spi_xcomm_ids
,
246 .probe
= spi_xcomm_probe
,
248 module_i2c_driver(spi_xcomm_driver
);
250 MODULE_LICENSE("GPL");
251 MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
252 MODULE_DESCRIPTION("Analog Devices AD-FMCOMMS1-EBZ board I2C-SPI bridge driver");