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
)
81 speed
= t
->speed_hz
? t
->speed_hz
: spi
->max_speed_hz
;
83 if (speed
!= spi_xcomm
->current_speed
) {
84 unsigned int divider
= DIV_ROUND_UP(SPI_XCOMM_CLOCK
, speed
);
86 *settings
|= SPI_XCOMM_SETTINGS_CLOCK_DIV_64
;
87 else if (divider
>= 16)
88 *settings
|= SPI_XCOMM_SETTINGS_CLOCK_DIV_16
;
90 *settings
|= SPI_XCOMM_SETTINGS_CLOCK_DIV_4
;
92 spi_xcomm
->current_speed
= speed
;
95 if (spi
->mode
& SPI_CPOL
)
96 *settings
|= SPI_XCOMM_SETTINGS_CPOL
;
98 *settings
&= ~SPI_XCOMM_SETTINGS_CPOL
;
100 if (spi
->mode
& SPI_CPHA
)
101 *settings
&= ~SPI_XCOMM_SETTINGS_CPHA
;
103 *settings
|= SPI_XCOMM_SETTINGS_CPHA
;
105 if (spi
->mode
& SPI_3WIRE
)
106 *settings
|= SPI_XCOMM_SETTINGS_3WIRE
;
108 *settings
&= ~SPI_XCOMM_SETTINGS_3WIRE
;
113 static int spi_xcomm_txrx_bufs(struct spi_xcomm
*spi_xcomm
,
114 struct spi_device
*spi
, struct spi_transfer
*t
)
119 spi_xcomm
->buf
[0] = SPI_XCOMM_CMD_WRITE
;
120 memcpy(spi_xcomm
->buf
+ 1, t
->tx_buf
, t
->len
);
122 ret
= i2c_master_send(spi_xcomm
->i2c
, spi_xcomm
->buf
, t
->len
+ 1);
125 else if (ret
!= t
->len
+ 1)
127 } else if (t
->rx_buf
) {
128 ret
= i2c_master_recv(spi_xcomm
->i2c
, t
->rx_buf
, t
->len
);
131 else if (ret
!= t
->len
)
138 static int spi_xcomm_transfer_one(struct spi_master
*master
,
139 struct spi_message
*msg
)
141 struct spi_xcomm
*spi_xcomm
= spi_master_get_devdata(master
);
142 unsigned int settings
= spi_xcomm
->settings
;
143 struct spi_device
*spi
= msg
->spi
;
144 unsigned cs_change
= 0;
145 struct spi_transfer
*t
;
146 bool is_first
= true;
152 spi_xcomm_chipselect(spi_xcomm
, spi
, true);
154 list_for_each_entry(t
, &msg
->transfers
, transfer_list
) {
156 if (!t
->tx_buf
&& !t
->rx_buf
&& t
->len
) {
161 status
= spi_xcomm_setup_transfer(spi_xcomm
, spi
, t
, &settings
);
165 is_last
= list_is_last(&t
->transfer_list
, &msg
->transfers
);
166 cs_change
= t
->cs_change
;
168 if (cs_change
^ is_last
)
174 spi_xcomm
->settings
= settings
;
175 status
= spi_xcomm_sync_config(spi_xcomm
, t
->len
);
178 } else if (settings
!= spi_xcomm
->settings
|| is_first
) {
179 spi_xcomm
->settings
= settings
;
180 status
= spi_xcomm_sync_config(spi_xcomm
, 0);
186 status
= spi_xcomm_txrx_bufs(spi_xcomm
, spi
, t
);
192 msg
->actual_length
+= status
;
197 udelay(t
->delay_usecs
);
202 if (status
!= 0 || !cs_change
)
203 spi_xcomm_chipselect(spi_xcomm
, spi
, false);
205 msg
->status
= status
;
206 spi_finalize_current_message(master
);
211 static int spi_xcomm_probe(struct i2c_client
*i2c
,
212 const struct i2c_device_id
*id
)
214 struct spi_xcomm
*spi_xcomm
;
215 struct spi_master
*master
;
218 master
= spi_alloc_master(&i2c
->dev
, sizeof(*spi_xcomm
));
222 spi_xcomm
= spi_master_get_devdata(master
);
223 spi_xcomm
->i2c
= i2c
;
225 master
->num_chipselect
= 16;
226 master
->mode_bits
= SPI_CPHA
| SPI_CPOL
| SPI_3WIRE
;
227 master
->bits_per_word_mask
= SPI_BPW_MASK(8);
228 master
->flags
= SPI_MASTER_HALF_DUPLEX
;
229 master
->transfer_one_message
= spi_xcomm_transfer_one
;
230 master
->dev
.of_node
= i2c
->dev
.of_node
;
231 i2c_set_clientdata(i2c
, master
);
233 ret
= devm_spi_register_master(&i2c
->dev
, master
);
235 spi_master_put(master
);
240 static const struct i2c_device_id spi_xcomm_ids
[] = {
245 static struct i2c_driver spi_xcomm_driver
= {
248 .owner
= THIS_MODULE
,
250 .id_table
= spi_xcomm_ids
,
251 .probe
= spi_xcomm_probe
,
253 module_i2c_driver(spi_xcomm_driver
);
255 MODULE_LICENSE("GPL");
256 MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
257 MODULE_DESCRIPTION("Analog Devices AD-FMCOMMS1-EBZ board I2C-SPI bridge driver");