x86/smpboot: Init apic mapping before usage
[cascardo/linux.git] / drivers / spi / spi-xcomm.c
1 /*
2  * Analog Devices AD-FMCOMMS1-EBZ board I2C-SPI bridge driver
3  *
4  * Copyright 2012 Analog Devices Inc.
5  * Author: Lars-Peter Clausen <lars@metafoo.de>
6  *
7  * Licensed under the GPL-2 or later.
8  */
9
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>
16
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
27
28 #define SPI_XCOMM_CMD_UPDATE_CONFIG     0x03
29 #define SPI_XCOMM_CMD_WRITE             0x04
30
31 #define SPI_XCOMM_CLOCK 48000000
32
33 struct spi_xcomm {
34         struct i2c_client *i2c;
35
36         uint16_t settings;
37         uint16_t chipselect;
38
39         unsigned int current_speed;
40
41         uint8_t buf[63];
42 };
43
44 static int spi_xcomm_sync_config(struct spi_xcomm *spi_xcomm, unsigned int len)
45 {
46         uint16_t settings;
47         uint8_t *buf = spi_xcomm->buf;
48
49         settings = spi_xcomm->settings;
50         settings |= len << SPI_XCOMM_SETTINGS_LEN_OFFSET;
51
52         buf[0] = SPI_XCOMM_CMD_UPDATE_CONFIG;
53         put_unaligned_be16(settings, &buf[1]);
54         put_unaligned_be16(spi_xcomm->chipselect, &buf[3]);
55
56         return i2c_master_send(spi_xcomm->i2c, buf, 5);
57 }
58
59 static void spi_xcomm_chipselect(struct spi_xcomm *spi_xcomm,
60         struct spi_device *spi, int is_active)
61 {
62         unsigned long cs = spi->chip_select;
63         uint16_t chipselect = spi_xcomm->chipselect;
64
65         if (is_active)
66                 chipselect |= BIT(cs);
67         else
68                 chipselect &= ~BIT(cs);
69
70         spi_xcomm->chipselect = chipselect;
71 }
72
73 static int spi_xcomm_setup_transfer(struct spi_xcomm *spi_xcomm,
74         struct spi_device *spi, struct spi_transfer *t, unsigned int *settings)
75 {
76         if (t->len > 62)
77                 return -EINVAL;
78
79         if (t->speed_hz != spi_xcomm->current_speed) {
80                 unsigned int divider;
81
82                 divider = DIV_ROUND_UP(SPI_XCOMM_CLOCK, t->speed_hz);
83                 if (divider >= 64)
84                         *settings |= SPI_XCOMM_SETTINGS_CLOCK_DIV_64;
85                 else if (divider >= 16)
86                         *settings |= SPI_XCOMM_SETTINGS_CLOCK_DIV_16;
87                 else
88                         *settings |= SPI_XCOMM_SETTINGS_CLOCK_DIV_4;
89
90                 spi_xcomm->current_speed = t->speed_hz;
91         }
92
93         if (spi->mode & SPI_CPOL)
94                 *settings |= SPI_XCOMM_SETTINGS_CPOL;
95         else
96                 *settings &= ~SPI_XCOMM_SETTINGS_CPOL;
97
98         if (spi->mode & SPI_CPHA)
99                 *settings &= ~SPI_XCOMM_SETTINGS_CPHA;
100         else
101                 *settings |= SPI_XCOMM_SETTINGS_CPHA;
102
103         if (spi->mode & SPI_3WIRE)
104                 *settings |= SPI_XCOMM_SETTINGS_3WIRE;
105         else
106                 *settings &= ~SPI_XCOMM_SETTINGS_3WIRE;
107
108         return 0;
109 }
110
111 static int spi_xcomm_txrx_bufs(struct spi_xcomm *spi_xcomm,
112         struct spi_device *spi, struct spi_transfer *t)
113 {
114         int ret;
115
116         if (t->tx_buf) {
117                 spi_xcomm->buf[0] = SPI_XCOMM_CMD_WRITE;
118                 memcpy(spi_xcomm->buf + 1, t->tx_buf, t->len);
119
120                 ret = i2c_master_send(spi_xcomm->i2c, spi_xcomm->buf, t->len + 1);
121                 if (ret < 0)
122                         return ret;
123                 else if (ret != t->len + 1)
124                         return -EIO;
125         } else if (t->rx_buf) {
126                 ret = i2c_master_recv(spi_xcomm->i2c, t->rx_buf, t->len);
127                 if (ret < 0)
128                         return ret;
129                 else if (ret != t->len)
130                         return -EIO;
131         }
132
133         return t->len;
134 }
135
136 static int spi_xcomm_transfer_one(struct spi_master *master,
137         struct spi_message *msg)
138 {
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;
145         int status = 0;
146         bool is_last;
147
148         spi_xcomm_chipselect(spi_xcomm, spi, true);
149
150         list_for_each_entry(t, &msg->transfers, transfer_list) {
151
152                 if (!t->tx_buf && !t->rx_buf && t->len) {
153                         status = -EINVAL;
154                         break;
155                 }
156
157                 status = spi_xcomm_setup_transfer(spi_xcomm, spi, t, &settings);
158                 if (status < 0)
159                         break;
160
161                 is_last = list_is_last(&t->transfer_list, &msg->transfers);
162                 cs_change = t->cs_change;
163
164                 if (cs_change ^ is_last)
165                         settings |= BIT(5);
166                 else
167                         settings &= ~BIT(5);
168
169                 if (t->rx_buf) {
170                         spi_xcomm->settings = settings;
171                         status = spi_xcomm_sync_config(spi_xcomm, t->len);
172                         if (status < 0)
173                                 break;
174                 } else if (settings != spi_xcomm->settings || is_first) {
175                         spi_xcomm->settings = settings;
176                         status = spi_xcomm_sync_config(spi_xcomm, 0);
177                         if (status < 0)
178                                 break;
179                 }
180
181                 if (t->len) {
182                         status = spi_xcomm_txrx_bufs(spi_xcomm, spi, t);
183
184                         if (status < 0)
185                                 break;
186
187                         if (status > 0)
188                                 msg->actual_length += status;
189                 }
190                 status = 0;
191
192                 if (t->delay_usecs)
193                         udelay(t->delay_usecs);
194
195                 is_first = false;
196         }
197
198         if (status != 0 || !cs_change)
199                 spi_xcomm_chipselect(spi_xcomm, spi, false);
200
201         msg->status = status;
202         spi_finalize_current_message(master);
203
204         return status;
205 }
206
207 static int spi_xcomm_probe(struct i2c_client *i2c,
208         const struct i2c_device_id *id)
209 {
210         struct spi_xcomm *spi_xcomm;
211         struct spi_master *master;
212         int ret;
213
214         master = spi_alloc_master(&i2c->dev, sizeof(*spi_xcomm));
215         if (!master)
216                 return -ENOMEM;
217
218         spi_xcomm = spi_master_get_devdata(master);
219         spi_xcomm->i2c = i2c;
220
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);
228
229         ret = devm_spi_register_master(&i2c->dev, master);
230         if (ret < 0)
231                 spi_master_put(master);
232
233         return ret;
234 }
235
236 static const struct i2c_device_id spi_xcomm_ids[] = {
237         { "spi-xcomm" },
238         { },
239 };
240 MODULE_DEVICE_TABLE(i2c, spi_xcomm_ids);
241
242 static struct i2c_driver spi_xcomm_driver = {
243         .driver = {
244                 .name   = "spi-xcomm",
245         },
246         .id_table       = spi_xcomm_ids,
247         .probe          = spi_xcomm_probe,
248 };
249 module_i2c_driver(spi_xcomm_driver);
250
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");