2 * Analog Devices AD-FMCOMMS1-EBZ board I2C-SPI bridge driver
4 * Copyright 2012 Analog Devices Inc.
5 * Author: Lars-Peter Clausen <lars@metafoo.de>
7 * Licensed under the GPL-2 or later.
10 #include <linux/kernel.h>
11 #include <linux/module.h>
12 #include <linux/delay.h>
13 #include <linux/i2c.h>
14 #include <linux/spi/spi.h>
15 #include <asm/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
31 #define SPI_XCOMM_CLOCK 48000000
34 struct i2c_client
*i2c
;
39 unsigned int current_speed
;
44 static int spi_xcomm_sync_config(struct spi_xcomm
*spi_xcomm
, unsigned int len
)
47 uint8_t *buf
= spi_xcomm
->buf
;
49 settings
= spi_xcomm
->settings
;
50 settings
|= len
<< SPI_XCOMM_SETTINGS_LEN_OFFSET
;
52 buf
[0] = SPI_XCOMM_CMD_UPDATE_CONFIG
;
53 put_unaligned_be16(settings
, &buf
[1]);
54 put_unaligned_be16(spi_xcomm
->chipselect
, &buf
[3]);
56 return i2c_master_send(spi_xcomm
->i2c
, buf
, 5);
59 static void spi_xcomm_chipselect(struct spi_xcomm
*spi_xcomm
,
60 struct spi_device
*spi
, int is_active
)
62 unsigned long cs
= spi
->chip_select
;
63 uint16_t chipselect
= spi_xcomm
->chipselect
;
66 chipselect
|= BIT(cs
);
68 chipselect
&= ~BIT(cs
);
70 spi_xcomm
->chipselect
= chipselect
;
73 static int spi_xcomm_setup_transfer(struct spi_xcomm
*spi_xcomm
,
74 struct spi_device
*spi
, struct spi_transfer
*t
, unsigned int *settings
)
79 if (t
->speed_hz
!= spi_xcomm
->current_speed
) {
82 divider
= DIV_ROUND_UP(SPI_XCOMM_CLOCK
, t
->speed_hz
);
84 *settings
|= SPI_XCOMM_SETTINGS_CLOCK_DIV_64
;
85 else if (divider
>= 16)
86 *settings
|= SPI_XCOMM_SETTINGS_CLOCK_DIV_16
;
88 *settings
|= SPI_XCOMM_SETTINGS_CLOCK_DIV_4
;
90 spi_xcomm
->current_speed
= t
->speed_hz
;
93 if (spi
->mode
& SPI_CPOL
)
94 *settings
|= SPI_XCOMM_SETTINGS_CPOL
;
96 *settings
&= ~SPI_XCOMM_SETTINGS_CPOL
;
98 if (spi
->mode
& SPI_CPHA
)
99 *settings
&= ~SPI_XCOMM_SETTINGS_CPHA
;
101 *settings
|= SPI_XCOMM_SETTINGS_CPHA
;
103 if (spi
->mode
& SPI_3WIRE
)
104 *settings
|= SPI_XCOMM_SETTINGS_3WIRE
;
106 *settings
&= ~SPI_XCOMM_SETTINGS_3WIRE
;
111 static int spi_xcomm_txrx_bufs(struct spi_xcomm
*spi_xcomm
,
112 struct spi_device
*spi
, struct spi_transfer
*t
)
117 spi_xcomm
->buf
[0] = SPI_XCOMM_CMD_WRITE
;
118 memcpy(spi_xcomm
->buf
+ 1, t
->tx_buf
, t
->len
);
120 ret
= i2c_master_send(spi_xcomm
->i2c
, spi_xcomm
->buf
, t
->len
+ 1);
123 else if (ret
!= t
->len
+ 1)
125 } else if (t
->rx_buf
) {
126 ret
= i2c_master_recv(spi_xcomm
->i2c
, t
->rx_buf
, t
->len
);
129 else if (ret
!= t
->len
)
136 static int spi_xcomm_transfer_one(struct spi_master
*master
,
137 struct spi_message
*msg
)
139 struct spi_xcomm
*spi_xcomm
= spi_master_get_devdata(master
);
140 unsigned int settings
= spi_xcomm
->settings
;
141 struct spi_device
*spi
= msg
->spi
;
142 unsigned cs_change
= 0;
143 struct spi_transfer
*t
;
144 bool is_first
= true;
148 spi_xcomm_chipselect(spi_xcomm
, spi
, true);
150 list_for_each_entry(t
, &msg
->transfers
, transfer_list
) {
152 if (!t
->tx_buf
&& !t
->rx_buf
&& t
->len
) {
157 status
= spi_xcomm_setup_transfer(spi_xcomm
, spi
, t
, &settings
);
161 is_last
= list_is_last(&t
->transfer_list
, &msg
->transfers
);
162 cs_change
= t
->cs_change
;
164 if (cs_change
^ is_last
)
170 spi_xcomm
->settings
= settings
;
171 status
= spi_xcomm_sync_config(spi_xcomm
, t
->len
);
174 } else if (settings
!= spi_xcomm
->settings
|| is_first
) {
175 spi_xcomm
->settings
= settings
;
176 status
= spi_xcomm_sync_config(spi_xcomm
, 0);
182 status
= spi_xcomm_txrx_bufs(spi_xcomm
, spi
, t
);
188 msg
->actual_length
+= status
;
193 udelay(t
->delay_usecs
);
198 if (status
!= 0 || !cs_change
)
199 spi_xcomm_chipselect(spi_xcomm
, spi
, false);
201 msg
->status
= status
;
202 spi_finalize_current_message(master
);
207 static int spi_xcomm_probe(struct i2c_client
*i2c
,
208 const struct i2c_device_id
*id
)
210 struct spi_xcomm
*spi_xcomm
;
211 struct spi_master
*master
;
214 master
= spi_alloc_master(&i2c
->dev
, sizeof(*spi_xcomm
));
218 spi_xcomm
= spi_master_get_devdata(master
);
219 spi_xcomm
->i2c
= i2c
;
221 master
->num_chipselect
= 16;
222 master
->mode_bits
= SPI_CPHA
| SPI_CPOL
| SPI_3WIRE
;
223 master
->bits_per_word_mask
= SPI_BPW_MASK(8);
224 master
->flags
= SPI_MASTER_HALF_DUPLEX
;
225 master
->transfer_one_message
= spi_xcomm_transfer_one
;
226 master
->dev
.of_node
= i2c
->dev
.of_node
;
227 i2c_set_clientdata(i2c
, master
);
229 ret
= devm_spi_register_master(&i2c
->dev
, master
);
231 spi_master_put(master
);
236 static const struct i2c_device_id spi_xcomm_ids
[] = {
240 MODULE_DEVICE_TABLE(i2c
, spi_xcomm_ids
);
242 static struct i2c_driver spi_xcomm_driver
= {
246 .id_table
= spi_xcomm_ids
,
247 .probe
= spi_xcomm_probe
,
249 module_i2c_driver(spi_xcomm_driver
);
251 MODULE_LICENSE("GPL");
252 MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
253 MODULE_DESCRIPTION("Analog Devices AD-FMCOMMS1-EBZ board I2C-SPI bridge driver");