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/init.h>
12 #include <linux/module.h>
13 #include <linux/delay.h>
14 #include <linux/i2c.h>
15 #include <linux/spi/spi.h>
16 #include <asm/unaligned.h>
18 #define SPI_XCOMM_SETTINGS_LEN_OFFSET 10
19 #define SPI_XCOMM_SETTINGS_3WIRE BIT(6)
20 #define SPI_XCOMM_SETTINGS_CS_HIGH BIT(5)
21 #define SPI_XCOMM_SETTINGS_SAMPLE_END BIT(4)
22 #define SPI_XCOMM_SETTINGS_CPHA BIT(3)
23 #define SPI_XCOMM_SETTINGS_CPOL BIT(2)
24 #define SPI_XCOMM_SETTINGS_CLOCK_DIV_MASK 0x3
25 #define SPI_XCOMM_SETTINGS_CLOCK_DIV_64 0x2
26 #define SPI_XCOMM_SETTINGS_CLOCK_DIV_16 0x1
27 #define SPI_XCOMM_SETTINGS_CLOCK_DIV_4 0x0
29 #define SPI_XCOMM_CMD_UPDATE_CONFIG 0x03
30 #define SPI_XCOMM_CMD_WRITE 0x04
32 #define SPI_XCOMM_CLOCK 48000000
35 struct i2c_client
*i2c
;
40 unsigned int current_speed
;
45 static int spi_xcomm_sync_config(struct spi_xcomm
*spi_xcomm
, unsigned int len
)
48 uint8_t *buf
= spi_xcomm
->buf
;
50 settings
= spi_xcomm
->settings
;
51 settings
|= len
<< SPI_XCOMM_SETTINGS_LEN_OFFSET
;
53 buf
[0] = SPI_XCOMM_CMD_UPDATE_CONFIG
;
54 put_unaligned_be16(settings
, &buf
[1]);
55 put_unaligned_be16(spi_xcomm
->chipselect
, &buf
[3]);
57 return i2c_master_send(spi_xcomm
->i2c
, buf
, 5);
60 static void spi_xcomm_chipselect(struct spi_xcomm
*spi_xcomm
,
61 struct spi_device
*spi
, int is_active
)
63 unsigned long cs
= spi
->chip_select
;
64 uint16_t chipselect
= spi_xcomm
->chipselect
;
67 chipselect
|= BIT(cs
);
69 chipselect
&= ~BIT(cs
);
71 spi_xcomm
->chipselect
= chipselect
;
74 static int spi_xcomm_setup_transfer(struct spi_xcomm
*spi_xcomm
,
75 struct spi_device
*spi
, struct spi_transfer
*t
, unsigned int *settings
)
82 speed
= t
->speed_hz
? t
->speed_hz
: spi
->max_speed_hz
;
84 if (speed
!= spi_xcomm
->current_speed
) {
85 unsigned int divider
= DIV_ROUND_UP(SPI_XCOMM_CLOCK
, speed
);
87 *settings
|= SPI_XCOMM_SETTINGS_CLOCK_DIV_64
;
88 else if (divider
>= 16)
89 *settings
|= SPI_XCOMM_SETTINGS_CLOCK_DIV_16
;
91 *settings
|= SPI_XCOMM_SETTINGS_CLOCK_DIV_4
;
93 spi_xcomm
->current_speed
= speed
;
96 if (spi
->mode
& SPI_CPOL
)
97 *settings
|= SPI_XCOMM_SETTINGS_CPOL
;
99 *settings
&= ~SPI_XCOMM_SETTINGS_CPOL
;
101 if (spi
->mode
& SPI_CPHA
)
102 *settings
&= ~SPI_XCOMM_SETTINGS_CPHA
;
104 *settings
|= SPI_XCOMM_SETTINGS_CPHA
;
106 if (spi
->mode
& SPI_3WIRE
)
107 *settings
|= SPI_XCOMM_SETTINGS_3WIRE
;
109 *settings
&= ~SPI_XCOMM_SETTINGS_3WIRE
;
114 static int spi_xcomm_txrx_bufs(struct spi_xcomm
*spi_xcomm
,
115 struct spi_device
*spi
, struct spi_transfer
*t
)
120 spi_xcomm
->buf
[0] = SPI_XCOMM_CMD_WRITE
;
121 memcpy(spi_xcomm
->buf
+ 1, t
->tx_buf
, t
->len
);
123 ret
= i2c_master_send(spi_xcomm
->i2c
, spi_xcomm
->buf
, t
->len
+ 1);
126 else if (ret
!= t
->len
+ 1)
128 } else if (t
->rx_buf
) {
129 ret
= i2c_master_recv(spi_xcomm
->i2c
, t
->rx_buf
, t
->len
);
132 else if (ret
!= t
->len
)
139 static int spi_xcomm_transfer_one(struct spi_master
*master
,
140 struct spi_message
*msg
)
142 struct spi_xcomm
*spi_xcomm
= spi_master_get_devdata(master
);
143 unsigned int settings
= spi_xcomm
->settings
;
144 struct spi_device
*spi
= msg
->spi
;
145 unsigned cs_change
= 0;
146 struct spi_transfer
*t
;
147 bool is_first
= true;
153 spi_xcomm_chipselect(spi_xcomm
, spi
, true);
155 list_for_each_entry(t
, &msg
->transfers
, transfer_list
) {
157 if (!t
->tx_buf
&& !t
->rx_buf
&& t
->len
) {
162 status
= spi_xcomm_setup_transfer(spi_xcomm
, spi
, t
, &settings
);
166 is_last
= list_is_last(&t
->transfer_list
, &msg
->transfers
);
167 cs_change
= t
->cs_change
;
169 if (cs_change
^ is_last
)
175 spi_xcomm
->settings
= settings
;
176 status
= spi_xcomm_sync_config(spi_xcomm
, t
->len
);
179 } else if (settings
!= spi_xcomm
->settings
|| is_first
) {
180 spi_xcomm
->settings
= settings
;
181 status
= spi_xcomm_sync_config(spi_xcomm
, 0);
187 status
= spi_xcomm_txrx_bufs(spi_xcomm
, spi
, t
);
193 msg
->actual_length
+= status
;
198 udelay(t
->delay_usecs
);
203 if (status
!= 0 || !cs_change
)
204 spi_xcomm_chipselect(spi_xcomm
, spi
, false);
206 msg
->status
= status
;
207 spi_finalize_current_message(master
);
212 static int spi_xcomm_probe(struct i2c_client
*i2c
,
213 const struct i2c_device_id
*id
)
215 struct spi_xcomm
*spi_xcomm
;
216 struct spi_master
*master
;
219 master
= spi_alloc_master(&i2c
->dev
, sizeof(*spi_xcomm
));
223 spi_xcomm
= spi_master_get_devdata(master
);
224 spi_xcomm
->i2c
= i2c
;
226 master
->num_chipselect
= 16;
227 master
->mode_bits
= SPI_CPHA
| SPI_CPOL
| SPI_3WIRE
;
228 master
->bits_per_word_mask
= SPI_BPW_MASK(8);
229 master
->flags
= SPI_MASTER_HALF_DUPLEX
;
230 master
->transfer_one_message
= spi_xcomm_transfer_one
;
231 master
->dev
.of_node
= i2c
->dev
.of_node
;
232 i2c_set_clientdata(i2c
, master
);
234 ret
= devm_spi_register_master(&i2c
->dev
, master
);
236 spi_master_put(master
);
241 static const struct i2c_device_id spi_xcomm_ids
[] = {
246 static struct i2c_driver spi_xcomm_driver
= {
249 .owner
= THIS_MODULE
,
251 .id_table
= spi_xcomm_ids
,
252 .probe
= spi_xcomm_probe
,
254 module_i2c_driver(spi_xcomm_driver
);
256 MODULE_LICENSE("GPL");
257 MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
258 MODULE_DESCRIPTION("Analog Devices AD-FMCOMMS1-EBZ board I2C-SPI bridge driver");