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/gpio/driver.h>
14 #include <linux/spi/spi.h>
15 #include <linux/unaligned.h>
17 #define SPI_XCOMM_SETTINGS_LEN_OFFSET 10
18 #define SPI_XCOMM_SETTINGS_3WIRE BIT(6)
19 #define SPI_XCOMM_SETTINGS_CS_HIGH BIT(5)
20 #define SPI_XCOMM_SETTINGS_SAMPLE_END BIT(4)
21 #define SPI_XCOMM_SETTINGS_CPHA BIT(3)
22 #define SPI_XCOMM_SETTINGS_CPOL BIT(2)
23 #define SPI_XCOMM_SETTINGS_CLOCK_DIV_MASK 0x3
24 #define SPI_XCOMM_SETTINGS_CLOCK_DIV_64 0x2
25 #define SPI_XCOMM_SETTINGS_CLOCK_DIV_16 0x1
26 #define SPI_XCOMM_SETTINGS_CLOCK_DIV_4 0x0
28 #define SPI_XCOMM_CMD_UPDATE_CONFIG 0x03
29 #define SPI_XCOMM_CMD_WRITE 0x04
30 #define SPI_XCOMM_CMD_GPIO_SET 0x05
32 #define SPI_XCOMM_CLOCK 48000000
35 struct i2c_client
*i2c
;
42 unsigned int current_speed
;
47 static void spi_xcomm_gpio_set_value(struct gpio_chip
*chip
,
48 unsigned int offset
, int val
)
50 struct spi_xcomm
*spi_xcomm
= gpiochip_get_data(chip
);
53 buf
[0] = SPI_XCOMM_CMD_GPIO_SET
;
56 i2c_master_send(spi_xcomm
->i2c
, buf
, 2);
59 static int spi_xcomm_gpio_get_direction(struct gpio_chip
*chip
,
62 return GPIO_LINE_DIRECTION_OUT
;
65 static int spi_xcomm_gpio_add(struct spi_xcomm
*spi_xcomm
)
67 struct device
*dev
= &spi_xcomm
->i2c
->dev
;
69 if (!IS_ENABLED(CONFIG_GPIOLIB
))
72 spi_xcomm
->gc
.get_direction
= spi_xcomm_gpio_get_direction
;
73 spi_xcomm
->gc
.set
= spi_xcomm_gpio_set_value
;
74 spi_xcomm
->gc
.can_sleep
= 1;
75 spi_xcomm
->gc
.base
= -1;
76 spi_xcomm
->gc
.ngpio
= 1;
77 spi_xcomm
->gc
.label
= spi_xcomm
->i2c
->name
;
78 spi_xcomm
->gc
.owner
= THIS_MODULE
;
80 return devm_gpiochip_add_data(dev
, &spi_xcomm
->gc
, spi_xcomm
);
83 static int spi_xcomm_sync_config(struct spi_xcomm
*spi_xcomm
, unsigned int len
)
86 u8
*buf
= spi_xcomm
->buf
;
88 settings
= spi_xcomm
->settings
;
89 settings
|= len
<< SPI_XCOMM_SETTINGS_LEN_OFFSET
;
91 buf
[0] = SPI_XCOMM_CMD_UPDATE_CONFIG
;
92 put_unaligned_be16(settings
, &buf
[1]);
93 put_unaligned_be16(spi_xcomm
->chipselect
, &buf
[3]);
95 return i2c_master_send(spi_xcomm
->i2c
, buf
, 5);
98 static void spi_xcomm_chipselect(struct spi_xcomm
*spi_xcomm
,
99 struct spi_device
*spi
, int is_active
)
101 unsigned long cs
= spi_get_chipselect(spi
, 0);
102 u16 chipselect
= spi_xcomm
->chipselect
;
105 chipselect
|= BIT(cs
);
107 chipselect
&= ~BIT(cs
);
109 spi_xcomm
->chipselect
= chipselect
;
112 static int spi_xcomm_setup_transfer(struct spi_xcomm
*spi_xcomm
,
113 struct spi_device
*spi
, struct spi_transfer
*t
,
114 unsigned int *settings
)
119 if (t
->speed_hz
!= spi_xcomm
->current_speed
) {
120 unsigned int divider
;
122 divider
= DIV_ROUND_UP(SPI_XCOMM_CLOCK
, t
->speed_hz
);
124 *settings
|= SPI_XCOMM_SETTINGS_CLOCK_DIV_64
;
125 else if (divider
>= 16)
126 *settings
|= SPI_XCOMM_SETTINGS_CLOCK_DIV_16
;
128 *settings
|= SPI_XCOMM_SETTINGS_CLOCK_DIV_4
;
130 spi_xcomm
->current_speed
= t
->speed_hz
;
133 if (spi
->mode
& SPI_CPOL
)
134 *settings
|= SPI_XCOMM_SETTINGS_CPOL
;
136 *settings
&= ~SPI_XCOMM_SETTINGS_CPOL
;
138 if (spi
->mode
& SPI_CPHA
)
139 *settings
&= ~SPI_XCOMM_SETTINGS_CPHA
;
141 *settings
|= SPI_XCOMM_SETTINGS_CPHA
;
143 if (spi
->mode
& SPI_3WIRE
)
144 *settings
|= SPI_XCOMM_SETTINGS_3WIRE
;
146 *settings
&= ~SPI_XCOMM_SETTINGS_3WIRE
;
151 static int spi_xcomm_txrx_bufs(struct spi_xcomm
*spi_xcomm
,
152 struct spi_device
*spi
, struct spi_transfer
*t
)
157 spi_xcomm
->buf
[0] = SPI_XCOMM_CMD_WRITE
;
158 memcpy(spi_xcomm
->buf
+ 1, t
->tx_buf
, t
->len
);
160 ret
= i2c_master_send(spi_xcomm
->i2c
, spi_xcomm
->buf
, t
->len
+ 1);
163 if (ret
!= t
->len
+ 1)
165 } else if (t
->rx_buf
) {
166 ret
= i2c_master_recv(spi_xcomm
->i2c
, t
->rx_buf
, t
->len
);
176 static int spi_xcomm_transfer_one(struct spi_controller
*host
,
177 struct spi_message
*msg
)
179 struct spi_xcomm
*spi_xcomm
= spi_controller_get_devdata(host
);
180 unsigned int settings
= spi_xcomm
->settings
;
181 struct spi_device
*spi
= msg
->spi
;
182 unsigned int cs_change
= 0;
183 struct spi_transfer
*t
;
184 bool is_first
= true;
188 spi_xcomm_chipselect(spi_xcomm
, spi
, true);
190 list_for_each_entry(t
, &msg
->transfers
, transfer_list
) {
191 if (!t
->tx_buf
&& !t
->rx_buf
&& t
->len
) {
196 status
= spi_xcomm_setup_transfer(spi_xcomm
, spi
, t
, &settings
);
200 is_last
= list_is_last(&t
->transfer_list
, &msg
->transfers
);
201 cs_change
= t
->cs_change
;
203 if (cs_change
^ is_last
)
209 spi_xcomm
->settings
= settings
;
210 status
= spi_xcomm_sync_config(spi_xcomm
, t
->len
);
213 } else if (settings
!= spi_xcomm
->settings
|| is_first
) {
214 spi_xcomm
->settings
= settings
;
215 status
= spi_xcomm_sync_config(spi_xcomm
, 0);
221 status
= spi_xcomm_txrx_bufs(spi_xcomm
, spi
, t
);
227 msg
->actual_length
+= status
;
231 spi_transfer_delay_exec(t
);
236 if (status
!= 0 || !cs_change
)
237 spi_xcomm_chipselect(spi_xcomm
, spi
, false);
239 msg
->status
= status
;
240 spi_finalize_current_message(host
);
245 static int spi_xcomm_probe(struct i2c_client
*i2c
)
247 struct spi_xcomm
*spi_xcomm
;
248 struct spi_controller
*host
;
251 host
= devm_spi_alloc_host(&i2c
->dev
, sizeof(*spi_xcomm
));
255 spi_xcomm
= spi_controller_get_devdata(host
);
256 spi_xcomm
->i2c
= i2c
;
258 host
->num_chipselect
= 16;
259 host
->mode_bits
= SPI_CPHA
| SPI_CPOL
| SPI_3WIRE
;
260 host
->bits_per_word_mask
= SPI_BPW_MASK(8);
261 host
->flags
= SPI_CONTROLLER_HALF_DUPLEX
;
262 host
->transfer_one_message
= spi_xcomm_transfer_one
;
263 host
->dev
.of_node
= i2c
->dev
.of_node
;
265 ret
= devm_spi_register_controller(&i2c
->dev
, host
);
269 return spi_xcomm_gpio_add(spi_xcomm
);
272 static const struct i2c_device_id spi_xcomm_ids
[] = {
276 MODULE_DEVICE_TABLE(i2c
, spi_xcomm_ids
);
278 static struct i2c_driver spi_xcomm_driver
= {
282 .id_table
= spi_xcomm_ids
,
283 .probe
= spi_xcomm_probe
,
285 module_i2c_driver(spi_xcomm_driver
);
287 MODULE_LICENSE("GPL");
288 MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
289 MODULE_DESCRIPTION("Analog Devices AD-FMCOMMS1-EBZ board I2C-SPI bridge driver");