diff options
-rw-r--r-- | drivers/mfd/Kconfig | 10 | ||||
-rw-r--r-- | drivers/mfd/Makefile | 1 | ||||
-rw-r--r-- | drivers/mfd/cros_ec_spi.c | 375 |
3 files changed, 386 insertions, 0 deletions
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 4e54b5b01295..94b45476893e 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig | |||
@@ -39,6 +39,16 @@ config MFD_CROS_EC_I2C | |||
39 | a checksum. Failing accesses will be retried three times to | 39 | a checksum. Failing accesses will be retried three times to |
40 | improve reliability. | 40 | improve reliability. |
41 | 41 | ||
42 | config MFD_CROS_EC_SPI | ||
43 | tristate "ChromeOS Embedded Controller (SPI)" | ||
44 | depends on MFD_CROS_EC && SPI | ||
45 | |||
46 | ---help--- | ||
47 | If you say Y here, you get support for talking to the ChromeOS EC | ||
48 | through a SPI bus, using a byte-level protocol. Since the EC's | ||
49 | response time cannot be guaranteed, we support ignoring | ||
50 | 'pre-amble' bytes before the response actually starts. | ||
51 | |||
42 | config MFD_88PM800 | 52 | config MFD_88PM800 |
43 | tristate "Support Marvell 88PM800" | 53 | tristate "Support Marvell 88PM800" |
44 | depends on I2C=y && GENERIC_HARDIRQS | 54 | depends on I2C=y && GENERIC_HARDIRQS |
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 895257bec849..f62a583b5c85 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile | |||
@@ -10,6 +10,7 @@ obj-$(CONFIG_MFD_SM501) += sm501.o | |||
10 | obj-$(CONFIG_MFD_ASIC3) += asic3.o tmio_core.o | 10 | obj-$(CONFIG_MFD_ASIC3) += asic3.o tmio_core.o |
11 | obj-$(CONFIG_MFD_CROS_EC) += cros_ec.o | 11 | obj-$(CONFIG_MFD_CROS_EC) += cros_ec.o |
12 | obj-$(CONFIG_MFD_CROS_EC_I2C) += cros_ec_i2c.o | 12 | obj-$(CONFIG_MFD_CROS_EC_I2C) += cros_ec_i2c.o |
13 | obj-$(CONFIG_MFD_CROS_EC_SPI) += cros_ec_spi.o | ||
13 | 14 | ||
14 | rtsx_pci-objs := rtsx_pcr.o rts5209.o rts5229.o rtl8411.o rts5227.o | 15 | rtsx_pci-objs := rtsx_pcr.o rts5209.o rts5229.o rtl8411.o rts5227.o |
15 | obj-$(CONFIG_MFD_RTSX_PCI) += rtsx_pci.o | 16 | obj-$(CONFIG_MFD_RTSX_PCI) += rtsx_pci.o |
diff --git a/drivers/mfd/cros_ec_spi.c b/drivers/mfd/cros_ec_spi.c new file mode 100644 index 000000000000..da2d1b4db1b2 --- /dev/null +++ b/drivers/mfd/cros_ec_spi.c | |||
@@ -0,0 +1,375 @@ | |||
1 | /* | ||
2 | * ChromeOS EC multi-function device (SPI) | ||
3 | * | ||
4 | * Copyright (C) 2012 Google, Inc | ||
5 | * | ||
6 | * This software is licensed under the terms of the GNU General Public | ||
7 | * License version 2, as published by the Free Software Foundation, and | ||
8 | * may be copied, distributed, and modified under those terms. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | */ | ||
15 | |||
16 | #include <linux/delay.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/mfd/cros_ec.h> | ||
20 | #include <linux/mfd/cros_ec_commands.h> | ||
21 | #include <linux/platform_device.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/spi/spi.h> | ||
24 | |||
25 | |||
26 | /* The header byte, which follows the preamble */ | ||
27 | #define EC_MSG_HEADER 0xec | ||
28 | |||
29 | /* | ||
30 | * Number of EC preamble bytes we read at a time. Since it takes | ||
31 | * about 400-500us for the EC to respond there is not a lot of | ||
32 | * point in tuning this. If the EC could respond faster then | ||
33 | * we could increase this so that might expect the preamble and | ||
34 | * message to occur in a single transaction. However, the maximum | ||
35 | * SPI transfer size is 256 bytes, so at 5MHz we need a response | ||
36 | * time of perhaps <320us (200 bytes / 1600 bits). | ||
37 | */ | ||
38 | #define EC_MSG_PREAMBLE_COUNT 32 | ||
39 | |||
40 | /* | ||
41 | * We must get a response from the EC in 5ms. This is a very long | ||
42 | * time, but the flash write command can take 2-3ms. The EC command | ||
43 | * processing is currently not very fast (about 500us). We could | ||
44 | * look at speeding this up and making the flash write command a | ||
45 | * 'slow' command, requiring a GET_STATUS wait loop, like flash | ||
46 | * erase. | ||
47 | */ | ||
48 | #define EC_MSG_DEADLINE_MS 5 | ||
49 | |||
50 | /* | ||
51 | * Time between raising the SPI chip select (for the end of a | ||
52 | * transaction) and dropping it again (for the next transaction). | ||
53 | * If we go too fast, the EC will miss the transaction. It seems | ||
54 | * that 50us is enough with the 16MHz STM32 EC. | ||
55 | */ | ||
56 | #define EC_SPI_RECOVERY_TIME_NS (50 * 1000) | ||
57 | |||
58 | /** | ||
59 | * struct cros_ec_spi - information about a SPI-connected EC | ||
60 | * | ||
61 | * @spi: SPI device we are connected to | ||
62 | * @last_transfer_ns: time that we last finished a transfer, or 0 if there | ||
63 | * if no record | ||
64 | */ | ||
65 | struct cros_ec_spi { | ||
66 | struct spi_device *spi; | ||
67 | s64 last_transfer_ns; | ||
68 | }; | ||
69 | |||
70 | static void debug_packet(struct device *dev, const char *name, u8 *ptr, | ||
71 | int len) | ||
72 | { | ||
73 | #ifdef DEBUG | ||
74 | int i; | ||
75 | |||
76 | dev_dbg(dev, "%s: ", name); | ||
77 | for (i = 0; i < len; i++) | ||
78 | dev_cont(dev, " %02x", ptr[i]); | ||
79 | #endif | ||
80 | } | ||
81 | |||
82 | /** | ||
83 | * cros_ec_spi_receive_response - Receive a response from the EC. | ||
84 | * | ||
85 | * This function has two phases: reading the preamble bytes (since if we read | ||
86 | * data from the EC before it is ready to send, we just get preamble) and | ||
87 | * reading the actual message. | ||
88 | * | ||
89 | * The received data is placed into ec_dev->din. | ||
90 | * | ||
91 | * @ec_dev: ChromeOS EC device | ||
92 | * @need_len: Number of message bytes we need to read | ||
93 | */ | ||
94 | static int cros_ec_spi_receive_response(struct cros_ec_device *ec_dev, | ||
95 | int need_len) | ||
96 | { | ||
97 | struct cros_ec_spi *ec_spi = ec_dev->priv; | ||
98 | struct spi_transfer trans; | ||
99 | struct spi_message msg; | ||
100 | u8 *ptr, *end; | ||
101 | int ret; | ||
102 | unsigned long deadline; | ||
103 | int todo; | ||
104 | |||
105 | /* Receive data until we see the header byte */ | ||
106 | deadline = jiffies + msecs_to_jiffies(EC_MSG_DEADLINE_MS); | ||
107 | do { | ||
108 | memset(&trans, '\0', sizeof(trans)); | ||
109 | trans.cs_change = 1; | ||
110 | trans.rx_buf = ptr = ec_dev->din; | ||
111 | trans.len = EC_MSG_PREAMBLE_COUNT; | ||
112 | |||
113 | spi_message_init(&msg); | ||
114 | spi_message_add_tail(&trans, &msg); | ||
115 | ret = spi_sync(ec_spi->spi, &msg); | ||
116 | if (ret < 0) { | ||
117 | dev_err(ec_dev->dev, "spi transfer failed: %d\n", ret); | ||
118 | return ret; | ||
119 | } | ||
120 | |||
121 | for (end = ptr + EC_MSG_PREAMBLE_COUNT; ptr != end; ptr++) { | ||
122 | if (*ptr == EC_MSG_HEADER) { | ||
123 | dev_dbg(ec_dev->dev, "msg found at %d\n", | ||
124 | ptr - ec_dev->din); | ||
125 | break; | ||
126 | } | ||
127 | } | ||
128 | |||
129 | if (time_after(jiffies, deadline)) { | ||
130 | dev_warn(ec_dev->dev, "EC failed to respond in time\n"); | ||
131 | return -ETIMEDOUT; | ||
132 | } | ||
133 | } while (ptr == end); | ||
134 | |||
135 | /* | ||
136 | * ptr now points to the header byte. Copy any valid data to the | ||
137 | * start of our buffer | ||
138 | */ | ||
139 | todo = end - ++ptr; | ||
140 | BUG_ON(todo < 0 || todo > ec_dev->din_size); | ||
141 | todo = min(todo, need_len); | ||
142 | memmove(ec_dev->din, ptr, todo); | ||
143 | ptr = ec_dev->din + todo; | ||
144 | dev_dbg(ec_dev->dev, "need %d, got %d bytes from preamble\n", | ||
145 | need_len, todo); | ||
146 | need_len -= todo; | ||
147 | |||
148 | /* Receive data until we have it all */ | ||
149 | while (need_len > 0) { | ||
150 | /* | ||
151 | * We can't support transfers larger than the SPI FIFO size | ||
152 | * unless we have DMA. We don't have DMA on the ISP SPI ports | ||
153 | * for Exynos. We need a way of asking SPI driver for | ||
154 | * maximum-supported transfer size. | ||
155 | */ | ||
156 | todo = min(need_len, 256); | ||
157 | dev_dbg(ec_dev->dev, "loop, todo=%d, need_len=%d, ptr=%d\n", | ||
158 | todo, need_len, ptr - ec_dev->din); | ||
159 | |||
160 | memset(&trans, '\0', sizeof(trans)); | ||
161 | trans.cs_change = 1; | ||
162 | trans.rx_buf = ptr; | ||
163 | trans.len = todo; | ||
164 | spi_message_init(&msg); | ||
165 | spi_message_add_tail(&trans, &msg); | ||
166 | |||
167 | /* send command to EC and read answer */ | ||
168 | BUG_ON((u8 *)trans.rx_buf - ec_dev->din + todo > | ||
169 | ec_dev->din_size); | ||
170 | ret = spi_sync(ec_spi->spi, &msg); | ||
171 | if (ret < 0) { | ||
172 | dev_err(ec_dev->dev, "spi transfer failed: %d\n", ret); | ||
173 | return ret; | ||
174 | } | ||
175 | |||
176 | debug_packet(ec_dev->dev, "interim", ptr, todo); | ||
177 | ptr += todo; | ||
178 | need_len -= todo; | ||
179 | } | ||
180 | |||
181 | dev_dbg(ec_dev->dev, "loop done, ptr=%d\n", ptr - ec_dev->din); | ||
182 | |||
183 | return 0; | ||
184 | } | ||
185 | |||
186 | /** | ||
187 | * cros_ec_command_spi_xfer - Transfer a message over SPI and receive the reply | ||
188 | * | ||
189 | * @ec_dev: ChromeOS EC device | ||
190 | * @ec_msg: Message to transfer | ||
191 | */ | ||
192 | static int cros_ec_command_spi_xfer(struct cros_ec_device *ec_dev, | ||
193 | struct cros_ec_msg *ec_msg) | ||
194 | { | ||
195 | struct cros_ec_spi *ec_spi = ec_dev->priv; | ||
196 | struct spi_transfer trans; | ||
197 | struct spi_message msg; | ||
198 | int i, len; | ||
199 | u8 *ptr; | ||
200 | int sum; | ||
201 | int ret = 0, final_ret; | ||
202 | struct timespec ts; | ||
203 | |||
204 | len = cros_ec_prepare_tx(ec_dev, ec_msg); | ||
205 | dev_dbg(ec_dev->dev, "prepared, len=%d\n", len); | ||
206 | |||
207 | /* If it's too soon to do another transaction, wait */ | ||
208 | if (ec_spi->last_transfer_ns) { | ||
209 | struct timespec ts; | ||
210 | unsigned long delay; /* The delay completed so far */ | ||
211 | |||
212 | ktime_get_ts(&ts); | ||
213 | delay = timespec_to_ns(&ts) - ec_spi->last_transfer_ns; | ||
214 | if (delay < EC_SPI_RECOVERY_TIME_NS) | ||
215 | ndelay(delay); | ||
216 | } | ||
217 | |||
218 | /* Transmit phase - send our message */ | ||
219 | debug_packet(ec_dev->dev, "out", ec_dev->dout, len); | ||
220 | memset(&trans, '\0', sizeof(trans)); | ||
221 | trans.tx_buf = ec_dev->dout; | ||
222 | trans.len = len; | ||
223 | trans.cs_change = 1; | ||
224 | spi_message_init(&msg); | ||
225 | spi_message_add_tail(&trans, &msg); | ||
226 | ret = spi_sync(ec_spi->spi, &msg); | ||
227 | |||
228 | /* Get the response */ | ||
229 | if (!ret) { | ||
230 | ret = cros_ec_spi_receive_response(ec_dev, | ||
231 | ec_msg->in_len + EC_MSG_TX_PROTO_BYTES); | ||
232 | } else { | ||
233 | dev_err(ec_dev->dev, "spi transfer failed: %d\n", ret); | ||
234 | } | ||
235 | |||
236 | /* turn off CS */ | ||
237 | spi_message_init(&msg); | ||
238 | final_ret = spi_sync(ec_spi->spi, &msg); | ||
239 | ktime_get_ts(&ts); | ||
240 | ec_spi->last_transfer_ns = timespec_to_ns(&ts); | ||
241 | if (!ret) | ||
242 | ret = final_ret; | ||
243 | if (ret < 0) { | ||
244 | dev_err(ec_dev->dev, "spi transfer failed: %d\n", ret); | ||
245 | return ret; | ||
246 | } | ||
247 | |||
248 | /* check response error code */ | ||
249 | ptr = ec_dev->din; | ||
250 | if (ptr[0]) { | ||
251 | dev_warn(ec_dev->dev, "command 0x%02x returned an error %d\n", | ||
252 | ec_msg->cmd, ptr[0]); | ||
253 | debug_packet(ec_dev->dev, "in_err", ptr, len); | ||
254 | return -EINVAL; | ||
255 | } | ||
256 | len = ptr[1]; | ||
257 | sum = ptr[0] + ptr[1]; | ||
258 | if (len > ec_msg->in_len) { | ||
259 | dev_err(ec_dev->dev, "packet too long (%d bytes, expected %d)", | ||
260 | len, ec_msg->in_len); | ||
261 | return -ENOSPC; | ||
262 | } | ||
263 | |||
264 | /* copy response packet payload and compute checksum */ | ||
265 | for (i = 0; i < len; i++) { | ||
266 | sum += ptr[i + 2]; | ||
267 | if (ec_msg->in_len) | ||
268 | ec_msg->in_buf[i] = ptr[i + 2]; | ||
269 | } | ||
270 | sum &= 0xff; | ||
271 | |||
272 | debug_packet(ec_dev->dev, "in", ptr, len + 3); | ||
273 | |||
274 | if (sum != ptr[len + 2]) { | ||
275 | dev_err(ec_dev->dev, | ||
276 | "bad packet checksum, expected %02x, got %02x\n", | ||
277 | sum, ptr[len + 2]); | ||
278 | return -EBADMSG; | ||
279 | } | ||
280 | |||
281 | return 0; | ||
282 | } | ||
283 | |||
284 | static int cros_ec_probe_spi(struct spi_device *spi) | ||
285 | { | ||
286 | struct device *dev = &spi->dev; | ||
287 | struct cros_ec_device *ec_dev; | ||
288 | struct cros_ec_spi *ec_spi; | ||
289 | int err; | ||
290 | |||
291 | spi->bits_per_word = 8; | ||
292 | spi->mode = SPI_MODE_0; | ||
293 | err = spi_setup(spi); | ||
294 | if (err < 0) | ||
295 | return err; | ||
296 | |||
297 | ec_spi = devm_kzalloc(dev, sizeof(*ec_spi), GFP_KERNEL); | ||
298 | if (ec_spi == NULL) | ||
299 | return -ENOMEM; | ||
300 | ec_spi->spi = spi; | ||
301 | ec_dev = devm_kzalloc(dev, sizeof(*ec_dev), GFP_KERNEL); | ||
302 | if (!ec_dev) | ||
303 | return -ENOMEM; | ||
304 | |||
305 | spi_set_drvdata(spi, ec_dev); | ||
306 | ec_dev->name = "SPI"; | ||
307 | ec_dev->dev = dev; | ||
308 | ec_dev->priv = ec_spi; | ||
309 | ec_dev->irq = spi->irq; | ||
310 | ec_dev->command_xfer = cros_ec_command_spi_xfer; | ||
311 | ec_dev->ec_name = ec_spi->spi->modalias; | ||
312 | ec_dev->phys_name = dev_name(&ec_spi->spi->dev); | ||
313 | ec_dev->parent = &ec_spi->spi->dev; | ||
314 | ec_dev->din_size = EC_MSG_BYTES + EC_MSG_PREAMBLE_COUNT; | ||
315 | ec_dev->dout_size = EC_MSG_BYTES; | ||
316 | |||
317 | err = cros_ec_register(ec_dev); | ||
318 | if (err) { | ||
319 | dev_err(dev, "cannot register EC\n"); | ||
320 | return err; | ||
321 | } | ||
322 | |||
323 | return 0; | ||
324 | } | ||
325 | |||
326 | static int cros_ec_remove_spi(struct spi_device *spi) | ||
327 | { | ||
328 | struct cros_ec_device *ec_dev; | ||
329 | |||
330 | ec_dev = spi_get_drvdata(spi); | ||
331 | cros_ec_remove(ec_dev); | ||
332 | |||
333 | return 0; | ||
334 | } | ||
335 | |||
336 | #ifdef CONFIG_PM_SLEEP | ||
337 | static int cros_ec_spi_suspend(struct device *dev) | ||
338 | { | ||
339 | struct cros_ec_device *ec_dev = dev_get_drvdata(dev); | ||
340 | |||
341 | return cros_ec_suspend(ec_dev); | ||
342 | } | ||
343 | |||
344 | static int cros_ec_spi_resume(struct device *dev) | ||
345 | { | ||
346 | struct cros_ec_device *ec_dev = dev_get_drvdata(dev); | ||
347 | |||
348 | return cros_ec_resume(ec_dev); | ||
349 | } | ||
350 | #endif | ||
351 | |||
352 | static SIMPLE_DEV_PM_OPS(cros_ec_spi_pm_ops, cros_ec_spi_suspend, | ||
353 | cros_ec_spi_resume); | ||
354 | |||
355 | static const struct spi_device_id cros_ec_spi_id[] = { | ||
356 | { "cros-ec-spi", 0 }, | ||
357 | { } | ||
358 | }; | ||
359 | MODULE_DEVICE_TABLE(spi, cros_ec_spi_id); | ||
360 | |||
361 | static struct spi_driver cros_ec_driver_spi = { | ||
362 | .driver = { | ||
363 | .name = "cros-ec-spi", | ||
364 | .owner = THIS_MODULE, | ||
365 | .pm = &cros_ec_spi_pm_ops, | ||
366 | }, | ||
367 | .probe = cros_ec_probe_spi, | ||
368 | .remove = cros_ec_remove_spi, | ||
369 | .id_table = cros_ec_spi_id, | ||
370 | }; | ||
371 | |||
372 | module_spi_driver(cros_ec_driver_spi); | ||
373 | |||
374 | MODULE_LICENSE("GPL"); | ||
375 | MODULE_DESCRIPTION("ChromeOS EC multi function device (SPI)"); | ||