blob: da9093738d4af723d8ef731cb89aeaa511d47d13 [file] [log] [blame]
Greg Kroah-Hartman83ddaaa2014-08-11 17:27:22 +08001/*
2 * SD/MMC Greybus driver.
3 *
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +01004 * Copyright 2014-2015 Google Inc.
5 * Copyright 2014-2015 Linaro Ltd.
Greg Kroah-Hartman83ddaaa2014-08-11 17:27:22 +08006 *
7 * Released under the GPLv2 only.
8 */
9
10#include <linux/kernel.h>
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +010011#include <linux/mmc/core.h>
Greg Kroah-Hartman83ddaaa2014-08-11 17:27:22 +080012#include <linux/mmc/host.h>
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +010013#include <linux/mmc/mmc.h>
14#include <linux/scatterlist.h>
15#include <linux/workqueue.h>
Alex Eldere1e9dbd2014-10-01 21:54:11 -050016
Greg Kroah-Hartman83ddaaa2014-08-11 17:27:22 +080017#include "greybus.h"
18
Greg Kroah-Hartman199d68d2014-08-30 16:20:22 -070019struct gb_sdio_host {
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +010020 struct gb_connection *connection;
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +010021 struct mmc_host *mmc;
22 struct mmc_request *mrq;
23 struct mutex lock; /* lock for this host */
24 size_t data_max;
25 void *xfer_buffer;
26 spinlock_t xfer; /* lock to cancel ongoing transfer */
27 bool xfer_stop;
Johan Hovoldb9154df2015-09-14 20:19:04 +020028 struct workqueue_struct *mrq_workqueue;
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +010029 struct work_struct mrqwork;
Rui Miguel Silvac36d31c2015-07-02 19:11:31 +010030 u8 queued_events;
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +010031 bool removed;
32 bool card_present;
33 bool read_only;
Greg Kroah-Hartman83ddaaa2014-08-11 17:27:22 +080034};
35
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +010036
Rui Miguel Silvaef0cc0e2015-07-02 19:11:30 +010037#define GB_SDIO_RSP_R1_R5_R6_R7 (GB_SDIO_RSP_PRESENT | GB_SDIO_RSP_CRC | \
38 GB_SDIO_RSP_OPCODE)
39#define GB_SDIO_RSP_R3_R4 (GB_SDIO_RSP_PRESENT)
40#define GB_SDIO_RSP_R2 (GB_SDIO_RSP_PRESENT | GB_SDIO_RSP_CRC | \
41 GB_SDIO_RSP_136)
42#define GB_SDIO_RSP_R1B (GB_SDIO_RSP_PRESENT | GB_SDIO_RSP_CRC | \
43 GB_SDIO_RSP_OPCODE | GB_SDIO_RSP_BUSY)
44
Rui Miguel Silva73f4a522015-07-02 19:11:35 +010045static inline bool single_op(struct mmc_command *cmd)
46{
47 uint32_t opcode = cmd->opcode;
48
49 return opcode == MMC_WRITE_BLOCK ||
50 opcode == MMC_READ_SINGLE_BLOCK;
51}
52
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +010053static void _gb_sdio_set_host_caps(struct gb_sdio_host *host, u32 r)
Greg Kroah-Hartman83ddaaa2014-08-11 17:27:22 +080054{
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +010055 u32 caps = 0;
56 u32 caps2 = 0;
57
Rui Miguel Silvaf064b872015-10-08 12:10:54 +010058 caps = ((r & GB_SDIO_CAP_NONREMOVABLE) ? MMC_CAP_NONREMOVABLE : 0) |
59 ((r & GB_SDIO_CAP_4_BIT_DATA) ? MMC_CAP_4_BIT_DATA : 0) |
60 ((r & GB_SDIO_CAP_8_BIT_DATA) ? MMC_CAP_8_BIT_DATA : 0) |
61 ((r & GB_SDIO_CAP_MMC_HS) ? MMC_CAP_MMC_HIGHSPEED : 0) |
62 ((r & GB_SDIO_CAP_SD_HS) ? MMC_CAP_SD_HIGHSPEED : 0) |
63 ((r & GB_SDIO_CAP_ERASE) ? MMC_CAP_ERASE : 0) |
64 ((r & GB_SDIO_CAP_1_2V_DDR) ? MMC_CAP_1_2V_DDR : 0) |
65 ((r & GB_SDIO_CAP_1_8V_DDR) ? MMC_CAP_1_8V_DDR : 0) |
66 ((r & GB_SDIO_CAP_POWER_OFF_CARD) ? MMC_CAP_POWER_OFF_CARD : 0) |
67 ((r & GB_SDIO_CAP_UHS_SDR12) ? MMC_CAP_UHS_SDR12 : 0) |
68 ((r & GB_SDIO_CAP_UHS_SDR25) ? MMC_CAP_UHS_SDR25 : 0) |
69 ((r & GB_SDIO_CAP_UHS_SDR50) ? MMC_CAP_UHS_SDR50 : 0) |
70 ((r & GB_SDIO_CAP_UHS_SDR104) ? MMC_CAP_UHS_SDR104 : 0) |
71 ((r & GB_SDIO_CAP_UHS_DDR50) ? MMC_CAP_UHS_DDR50 : 0) |
72 ((r & GB_SDIO_CAP_DRIVER_TYPE_A) ? MMC_CAP_DRIVER_TYPE_A : 0) |
73 ((r & GB_SDIO_CAP_DRIVER_TYPE_C) ? MMC_CAP_DRIVER_TYPE_C : 0) |
74 ((r & GB_SDIO_CAP_DRIVER_TYPE_D) ? MMC_CAP_DRIVER_TYPE_D : 0);
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +010075
Rui Miguel Silvaf064b872015-10-08 12:10:54 +010076 caps2 = ((r & GB_SDIO_CAP_HS200_1_2V) ? MMC_CAP2_HS200_1_2V_SDR : 0) |
Rui Miguel Silva5656ab92015-06-24 23:20:26 +010077#ifdef MMC_HS400_SUPPORTED
Rui Miguel Silvaf064b872015-10-08 12:10:54 +010078 ((r & GB_SDIO_CAP_HS400_1_2V) ? MMC_CAP2_HS400_1_2V : 0) |
79 ((r & GB_SDIO_CAP_HS400_1_8V) ? MMC_CAP2_HS400_1_8V : 0) |
Rui Miguel Silva5656ab92015-06-24 23:20:26 +010080#endif
Rui Miguel Silvaf064b872015-10-08 12:10:54 +010081 ((r & GB_SDIO_CAP_HS200_1_8V) ? MMC_CAP2_HS200_1_8V_SDR : 0);
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +010082
Rui Miguel Silvaf85451d2015-07-02 19:11:36 +010083 host->mmc->caps = caps | MMC_CAP_NEEDS_POLL;
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +010084 host->mmc->caps2 = caps2;
85
86 if (caps & MMC_CAP_NONREMOVABLE)
87 host->card_present = true;
Greg Kroah-Hartman83ddaaa2014-08-11 17:27:22 +080088}
89
Rui Miguel Silvadcb8d8d2015-10-08 12:10:53 +010090static u32 _gb_sdio_get_host_ocr(u32 ocr)
91{
92 return (((ocr & GB_SDIO_VDD_165_195) ? MMC_VDD_165_195 : 0) |
93 ((ocr & GB_SDIO_VDD_20_21) ? MMC_VDD_20_21 : 0) |
94 ((ocr & GB_SDIO_VDD_21_22) ? MMC_VDD_21_22 : 0) |
95 ((ocr & GB_SDIO_VDD_22_23) ? MMC_VDD_22_23 : 0) |
96 ((ocr & GB_SDIO_VDD_23_24) ? MMC_VDD_23_24 : 0) |
97 ((ocr & GB_SDIO_VDD_24_25) ? MMC_VDD_24_25 : 0) |
98 ((ocr & GB_SDIO_VDD_25_26) ? MMC_VDD_25_26 : 0) |
99 ((ocr & GB_SDIO_VDD_26_27) ? MMC_VDD_26_27 : 0) |
100 ((ocr & GB_SDIO_VDD_27_28) ? MMC_VDD_27_28 : 0) |
101 ((ocr & GB_SDIO_VDD_28_29) ? MMC_VDD_28_29 : 0) |
102 ((ocr & GB_SDIO_VDD_29_30) ? MMC_VDD_29_30 : 0) |
103 ((ocr & GB_SDIO_VDD_30_31) ? MMC_VDD_30_31 : 0) |
104 ((ocr & GB_SDIO_VDD_31_32) ? MMC_VDD_31_32 : 0) |
105 ((ocr & GB_SDIO_VDD_32_33) ? MMC_VDD_32_33 : 0) |
106 ((ocr & GB_SDIO_VDD_33_34) ? MMC_VDD_33_34 : 0) |
107 ((ocr & GB_SDIO_VDD_34_35) ? MMC_VDD_34_35 : 0) |
108 ((ocr & GB_SDIO_VDD_35_36) ? MMC_VDD_35_36 : 0)
109 );
110}
111
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +0100112static int gb_sdio_get_caps(struct gb_sdio_host *host)
Greg Kroah-Hartman83ddaaa2014-08-11 17:27:22 +0800113{
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +0100114 struct gb_sdio_get_caps_response response;
115 struct mmc_host *mmc = host->mmc;
116 u16 data_max;
117 u32 blksz;
Rui Miguel Silvadcb8d8d2015-10-08 12:10:53 +0100118 u32 ocr;
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +0100119 u32 r;
120 int ret;
Greg Kroah-Hartman83ddaaa2014-08-11 17:27:22 +0800121
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +0100122 ret = gb_operation_sync(host->connection, GB_SDIO_TYPE_GET_CAPABILITIES,
123 NULL, 0, &response, sizeof(response));
124 if (ret < 0)
125 return ret;
126 r = le32_to_cpu(response.caps);
127
128 _gb_sdio_set_host_caps(host, r);
129
130 /* get the max block size that could fit our payload */
131 data_max = gb_operation_get_payload_size_max(host->connection);
132 data_max = min(data_max - sizeof(struct gb_sdio_transfer_request),
133 data_max - sizeof(struct gb_sdio_transfer_response));
134
135 blksz = min(le16_to_cpu(response.max_blk_size), data_max);
136 blksz = max_t(u32, 512, blksz);
137
138 mmc->max_blk_size = rounddown_pow_of_two(blksz);
139 mmc->max_blk_count = le16_to_cpu(response.max_blk_count);
140 host->data_max = data_max;
141
142 /* get ocr supported values */
Rui Miguel Silvadcb8d8d2015-10-08 12:10:53 +0100143 ocr = _gb_sdio_get_host_ocr(le32_to_cpu(response.ocr));
144 mmc->ocr_avail = ocr;
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +0100145 mmc->ocr_avail_sdio = mmc->ocr_avail;
146 mmc->ocr_avail_sd = mmc->ocr_avail;
147 mmc->ocr_avail_mmc = mmc->ocr_avail;
148
Rui Miguel Silvae0f875c2015-10-08 12:10:51 +0100149 /* get frequency range values */
150 mmc->f_min = le32_to_cpu(response.f_min);
151 mmc->f_max = le32_to_cpu(response.f_max);
152
Greg Kroah-Hartman83ddaaa2014-08-11 17:27:22 +0800153 return 0;
154}
155
Rui Miguel Silvac36d31c2015-07-02 19:11:31 +0100156static void _gb_queue_event(struct gb_sdio_host *host, u8 event)
157{
158 if (event & GB_SDIO_CARD_INSERTED)
159 host->queued_events &= ~GB_SDIO_CARD_REMOVED;
160 else if (event & GB_SDIO_CARD_REMOVED)
161 host->queued_events &= ~GB_SDIO_CARD_INSERTED;
162
163 host->queued_events |= event;
164}
165
166static int _gb_sdio_process_events(struct gb_sdio_host *host, u8 event)
167{
168 u8 state_changed = 0;
169
170 if (event & GB_SDIO_CARD_INSERTED) {
Rui Miguel Silva6cac7dc2015-10-08 12:10:52 +0100171 if (host->mmc->caps & MMC_CAP_NONREMOVABLE)
Rui Miguel Silvac36d31c2015-07-02 19:11:31 +0100172 return 0;
173 if (host->card_present)
174 return 0;
175 host->card_present = true;
176 state_changed = 1;
177 }
178
179 if (event & GB_SDIO_CARD_REMOVED) {
Rui Miguel Silva6cac7dc2015-10-08 12:10:52 +0100180 if (host->mmc->caps & MMC_CAP_NONREMOVABLE)
Rui Miguel Silvac36d31c2015-07-02 19:11:31 +0100181 return 0;
182 if (!(host->card_present))
183 return 0;
184 host->card_present = false;
185 state_changed = 1;
186 }
187
188 if (event & GB_SDIO_WP) {
189 host->read_only = true;
190 }
191
192 if (state_changed) {
193 dev_info(mmc_dev(host->mmc), "card %s now event\n",
194 (host->card_present ? "inserted" : "removed"));
195 mmc_detect_change(host->mmc, 0);
196 }
197
198 return 0;
199}
200
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +0100201static int gb_sdio_event_recv(u8 type, struct gb_operation *op)
202{
203 struct gb_connection *connection = op->connection;
204 struct gb_sdio_host *host = connection->private;
205 struct gb_message *request;
206 struct gb_sdio_event_request *payload;
Rui Miguel Silvac36d31c2015-07-02 19:11:31 +0100207 int ret = 0;
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +0100208 u8 event;
209
210 if (type != GB_SDIO_TYPE_EVENT) {
Greg Kroah-Hartman61c80572015-10-14 11:19:42 -0700211 dev_err(&connection->bundle->dev,
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +0100212 "unsupported unsolicited event: %u\n", type);
213 return -EINVAL;
214 }
215
216 request = op->request;
217
Viresh Kumarf1f6fa42015-08-08 08:09:32 +0530218 if (request->payload_size < sizeof(*payload)) {
219 dev_err(mmc_dev(host->mmc), "wrong event size received (%zu < %zu)\n",
220 request->payload_size, sizeof(*payload));
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +0100221 return -EINVAL;
222 }
223
224 payload = request->payload;
225 event = payload->event;
226
Rui Miguel Silvac36d31c2015-07-02 19:11:31 +0100227 if (host->removed)
228 _gb_queue_event(host, event);
229 else
230 ret = _gb_sdio_process_events(host, event);
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +0100231
Rui Miguel Silvac36d31c2015-07-02 19:11:31 +0100232 return ret;
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +0100233}
234
235static int gb_sdio_set_ios(struct gb_sdio_host *host,
236 struct gb_sdio_set_ios_request *request)
237{
238 return gb_operation_sync(host->connection, GB_SDIO_TYPE_SET_IOS,
239 request, sizeof(*request), NULL, 0);
240}
241
242static int _gb_sdio_send(struct gb_sdio_host *host, struct mmc_data *data,
243 size_t len, u16 nblocks, off_t skip)
244{
245 struct gb_sdio_transfer_request *request;
246 struct gb_sdio_transfer_response response;
247 struct scatterlist *sg = data->sg;
248 unsigned int sg_len = data->sg_len;
249 size_t copied;
250 u16 send_blksz;
251 u16 send_blocks;
252 int ret;
253
254 WARN_ON(len > host->data_max);
255
256 request = host->xfer_buffer;
257 request->data_flags = (data->flags >> 8);
258 request->data_blocks = cpu_to_le16(nblocks);
259 request->data_blksz = cpu_to_le16(data->blksz);
260
Rui Miguel Silva9ddf1332015-07-02 19:11:37 +0100261 copied = sg_pcopy_to_buffer(sg, sg_len, &request->data[0], len, skip);
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +0100262
263 if (copied != len)
264 return -EINVAL;
265
266 ret = gb_operation_sync(host->connection, GB_SDIO_TYPE_TRANSFER,
Rui Miguel Silva9ddf1332015-07-02 19:11:37 +0100267 request, len + sizeof(*request),
268 &response, sizeof(response));
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +0100269 if (ret < 0)
270 return ret;
271
272 send_blocks = le16_to_cpu(response.data_blocks);
273 send_blksz = le16_to_cpu(response.data_blksz);
274
Rui Miguel Silva9ddf1332015-07-02 19:11:37 +0100275 if (len != send_blksz * send_blocks) {
276 dev_err(mmc_dev(host->mmc), "send: size received: %zu != %d\n",
277 len, send_blksz * send_blocks);
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +0100278 return -EINVAL;
Rui Miguel Silva9ddf1332015-07-02 19:11:37 +0100279 }
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +0100280
281 return ret;
282}
283
284static int _gb_sdio_recv(struct gb_sdio_host *host, struct mmc_data *data,
285 size_t len, u16 nblocks, off_t skip)
286{
287 struct gb_sdio_transfer_request request;
288 struct gb_sdio_transfer_response *response;
289 struct scatterlist *sg = data->sg;
290 unsigned int sg_len = data->sg_len;
291 size_t copied;
292 u16 recv_blksz;
293 u16 recv_blocks;
294 int ret;
295
296 WARN_ON(len > host->data_max);
297
298 request.data_flags = (data->flags >> 8);
299 request.data_blocks = cpu_to_le16(nblocks);
300 request.data_blksz = cpu_to_le16(data->blksz);
301
302 response = host->xfer_buffer;
303
304 ret = gb_operation_sync(host->connection, GB_SDIO_TYPE_TRANSFER,
Rui Miguel Silva9ddf1332015-07-02 19:11:37 +0100305 &request, sizeof(request), response, len +
306 sizeof(*response));
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +0100307 if (ret < 0)
308 return ret;
309
310 recv_blocks = le16_to_cpu(response->data_blocks);
311 recv_blksz = le16_to_cpu(response->data_blksz);
312
Rui Miguel Silva9ddf1332015-07-02 19:11:37 +0100313 if (len != recv_blksz * recv_blocks) {
314 dev_err(mmc_dev(host->mmc), "recv: size received: %d != %zu\n",
315 recv_blksz * recv_blocks, len);
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +0100316 return -EINVAL;
Rui Miguel Silva9ddf1332015-07-02 19:11:37 +0100317 }
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +0100318
Rui Miguel Silva9ddf1332015-07-02 19:11:37 +0100319 copied = sg_pcopy_from_buffer(sg, sg_len, &response->data[0], len,
320 skip);
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +0100321 if (copied != len)
322 return -EINVAL;
323
324 return 0;
325}
326
Rui Miguel Silva882edf52015-07-02 19:11:34 +0100327static int gb_sdio_transfer(struct gb_sdio_host *host, struct mmc_data *data)
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +0100328{
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +0100329 size_t left, len;
330 off_t skip = 0;
331 int ret = 0;
332 u16 nblocks;
333
Rui Miguel Silva73f4a522015-07-02 19:11:35 +0100334 if (single_op(data->mrq->cmd) && data->blocks > 1) {
335 ret = -ETIMEDOUT;
336 goto out;
337 }
338
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +0100339 left = data->blksz * data->blocks;
340
341 while (left) {
342 /* check is a stop transmission is pending */
343 spin_lock(&host->xfer);
344 if (host->xfer_stop) {
345 host->xfer_stop = false;
346 spin_unlock(&host->xfer);
347 ret = -EINTR;
348 goto out;
349 }
350 spin_unlock(&host->xfer);
351 len = min(left, host->data_max);
Rui Miguel Silva9ddf1332015-07-02 19:11:37 +0100352 nblocks = len / data->blksz;
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +0100353 len = nblocks * data->blksz;
354
355 if (data->flags & MMC_DATA_READ) {
356 ret = _gb_sdio_recv(host, data, len, nblocks, skip);
357 if (ret < 0)
358 goto out;
359 } else {
360 ret = _gb_sdio_send(host, data, len, nblocks, skip);
361 if (ret < 0)
362 goto out;
363 }
364 data->bytes_xfered += len;
365 left -= len;
366 skip += len;
367 }
368
369out:
370 data->error = ret;
371 return ret;
372}
373
374static int gb_sdio_command(struct gb_sdio_host *host, struct mmc_command *cmd)
375{
Rui Miguel Silva10ed1932015-10-15 23:56:51 +0100376 struct gb_sdio_command_request request = {0};
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +0100377 struct gb_sdio_command_response response;
Rui Miguel Silva10ed1932015-10-15 23:56:51 +0100378 struct mmc_data *data = host->mrq->data;
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +0100379 u8 cmd_flags;
380 u8 cmd_type;
381 int i;
Rui Miguel Silvab6789ee2015-10-15 23:56:52 +0100382 int ret;
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +0100383
384 switch (mmc_resp_type(cmd)) {
385 case MMC_RSP_NONE:
386 cmd_flags = GB_SDIO_RSP_NONE;
387 break;
388 case MMC_RSP_R1:
389 cmd_flags = GB_SDIO_RSP_R1_R5_R6_R7;
390 break;
391 case MMC_RSP_R1B:
392 cmd_flags = GB_SDIO_RSP_R1B;
393 break;
394 case MMC_RSP_R2:
395 cmd_flags = GB_SDIO_RSP_R2;
396 break;
397 case MMC_RSP_R3:
398 cmd_flags = GB_SDIO_RSP_R3_R4;
Rui Miguel Silva73f4a522015-07-02 19:11:35 +0100399 break;
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +0100400 default:
Viresh Kumarb933fa42015-12-04 21:30:10 +0530401 dev_err(mmc_dev(host->mmc), "cmd flag invalid 0x%04x\n",
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +0100402 mmc_resp_type(cmd));
403 ret = -EINVAL;
404 goto out;
405 }
406
407 switch (mmc_cmd_type(cmd)) {
408 case MMC_CMD_BC:
409 cmd_type = GB_SDIO_CMD_BC;
410 break;
411 case MMC_CMD_BCR:
412 cmd_type = GB_SDIO_CMD_BCR;
413 break;
414 case MMC_CMD_AC:
415 cmd_type = GB_SDIO_CMD_AC;
416 break;
417 case MMC_CMD_ADTC:
418 cmd_type = GB_SDIO_CMD_ADTC;
419 break;
420 default:
Viresh Kumarb933fa42015-12-04 21:30:10 +0530421 dev_err(mmc_dev(host->mmc), "cmd type invalid 0x%04x\n",
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +0100422 mmc_cmd_type(cmd));
423 ret = -EINVAL;
424 goto out;
425 }
426
427 request.cmd = cmd->opcode;
428 request.cmd_flags = cmd_flags;
429 request.cmd_type = cmd_type;
430 request.cmd_arg = cpu_to_le32(cmd->arg);
Rui Miguel Silva10ed1932015-10-15 23:56:51 +0100431 /* some controllers need to know at command time data details */
432 if (data) {
433 request.data_blocks = cpu_to_le16(data->blocks);
434 request.data_blksz = cpu_to_le16(data->blksz);
435 }
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +0100436
437 ret = gb_operation_sync(host->connection, GB_SDIO_TYPE_COMMAND,
438 &request, sizeof(request), &response,
439 sizeof(response));
440 if (ret < 0)
441 goto out;
442
443 /* no response expected */
444 if (cmd_flags & GB_SDIO_RSP_NONE)
445 goto out;
446
447 /* long response expected */
448 if (cmd_flags & GB_SDIO_RSP_R2)
449 for (i = 0; i < 4; i++)
450 cmd->resp[i] = le32_to_cpu(response.resp[i]);
451 else
452 cmd->resp[0] = le32_to_cpu(response.resp[0]);
453
454out:
455 cmd->error = ret;
456 return ret;
457}
458
459static void gb_sdio_mrq_work(struct work_struct *work)
460{
461 struct gb_sdio_host *host;
462 struct mmc_request *mrq;
463 int ret;
464
465 host = container_of(work, struct gb_sdio_host, mrqwork);
466
467 mutex_lock(&host->lock);
Phong Tran93a99e82015-06-26 21:05:13 +0700468 mrq = host->mrq;
469 if (!mrq) {
470 mutex_unlock(&host->lock);
471 dev_err(mmc_dev(host->mmc), "mmc request is NULL");
472 return;
473 }
474
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +0100475 if (host->removed) {
476 mrq->cmd->error = -ESHUTDOWN;
477 goto done;
478 }
479
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +0100480 if (mrq->sbc) {
481 ret = gb_sdio_command(host, mrq->sbc);
482 if (ret < 0)
483 goto done;
484 }
485
486 ret = gb_sdio_command(host, mrq->cmd);
487 if (ret < 0)
488 goto done;
489
490 if (mrq->data) {
Rui Miguel Silvab6789ee2015-10-15 23:56:52 +0100491 ret = gb_sdio_transfer(host, mrq->data);
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +0100492 if (ret < 0)
493 goto done;
494 }
495
Rui Miguel Silva7a5cd5a2015-07-02 19:11:33 +0100496 if (mrq->stop) {
497 ret = gb_sdio_command(host, mrq->stop);
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +0100498 if (ret < 0)
499 goto done;
500 }
501
502done:
Phong Tran93a99e82015-06-26 21:05:13 +0700503 host->mrq = NULL;
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +0100504 mutex_unlock(&host->lock);
505 mmc_request_done(host->mmc, mrq);
506}
507
508static void gb_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
509{
510 struct gb_sdio_host *host = mmc_priv(mmc);
511 struct mmc_command *cmd = mrq->cmd;
512
513 /* Check if it is a cancel to ongoing transfer */
514 if (cmd->opcode == MMC_STOP_TRANSMISSION) {
515 spin_lock(&host->xfer);
516 host->xfer_stop = true;
517 spin_unlock(&host->xfer);
518 }
519
520 mutex_lock(&host->lock);
521
522 WARN_ON(host->mrq);
523 host->mrq = mrq;
524
525 if (host->removed) {
526 mrq->cmd->error = -ESHUTDOWN;
527 goto out;
528 }
529 if (!host->card_present) {
530 mrq->cmd->error = -ENOMEDIUM;
531 goto out;
532 }
533
Johan Hovoldb9154df2015-09-14 20:19:04 +0200534 queue_work(host->mrq_workqueue, &host->mrqwork);
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +0100535
536 mutex_unlock(&host->lock);
537 return;
538
539out:
540 host->mrq = NULL;
541 mutex_unlock(&host->lock);
542 mmc_request_done(mmc, mrq);
543}
544
545static void gb_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
546{
547 struct gb_sdio_host *host = mmc_priv(mmc);
548 struct gb_sdio_set_ios_request request;
549 int ret;
550 u8 power_mode;
551 u8 bus_width;
552 u8 timing;
553 u8 signal_voltage;
554 u8 drv_type;
555
556 mutex_lock(&host->lock);
557 request.clock = cpu_to_le32(ios->clock);
558 request.vdd = cpu_to_le32(1 << ios->vdd);
559
560 request.bus_mode = (ios->bus_mode == MMC_BUSMODE_OPENDRAIN ?
561 GB_SDIO_BUSMODE_OPENDRAIN :
562 GB_SDIO_BUSMODE_PUSHPULL);
563
564 switch (ios->power_mode) {
565 case MMC_POWER_OFF:
Rui Miguel Silva5656ab92015-06-24 23:20:26 +0100566 default:
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +0100567 power_mode = GB_SDIO_POWER_OFF;
568 break;
569 case MMC_POWER_UP:
570 power_mode = GB_SDIO_POWER_UP;
571 break;
572 case MMC_POWER_ON:
573 power_mode = GB_SDIO_POWER_ON;
574 break;
Rui Miguel Silva5656ab92015-06-24 23:20:26 +0100575#ifdef MMC_POWER_UNDEFINED_SUPPORTED
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +0100576 case MMC_POWER_UNDEFINED:
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +0100577 power_mode = GB_SDIO_POWER_UNDEFINED;
578 break;
Rui Miguel Silva5656ab92015-06-24 23:20:26 +0100579#endif
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +0100580 }
581 request.power_mode = power_mode;
582
583 switch (ios->bus_width) {
584 case MMC_BUS_WIDTH_1:
585 bus_width = GB_SDIO_BUS_WIDTH_1;
586 break;
587 case MMC_BUS_WIDTH_4:
588 default:
589 bus_width = GB_SDIO_BUS_WIDTH_4;
590 break;
591 case MMC_BUS_WIDTH_8:
592 bus_width = GB_SDIO_BUS_WIDTH_8;
593 break;
594 }
595 request.bus_width = bus_width;
596
597 switch (ios->timing) {
598 case MMC_TIMING_LEGACY:
599 default:
600 timing = GB_SDIO_TIMING_LEGACY;
601 break;
602 case MMC_TIMING_MMC_HS:
603 timing = GB_SDIO_TIMING_MMC_HS;
604 break;
605 case MMC_TIMING_SD_HS:
606 timing = GB_SDIO_TIMING_SD_HS;
607 break;
608 case MMC_TIMING_UHS_SDR12:
609 timing = GB_SDIO_TIMING_UHS_SDR12;
610 break;
611 case MMC_TIMING_UHS_SDR25:
612 timing = GB_SDIO_TIMING_UHS_SDR25;
613 break;
614 case MMC_TIMING_UHS_SDR50:
615 timing = GB_SDIO_TIMING_UHS_SDR50;
616 break;
617 case MMC_TIMING_UHS_SDR104:
618 timing = GB_SDIO_TIMING_UHS_SDR104;
619 break;
620 case MMC_TIMING_UHS_DDR50:
621 timing = GB_SDIO_TIMING_UHS_DDR50;
622 break;
Rui Miguel Silva5656ab92015-06-24 23:20:26 +0100623#ifdef MMC_DDR52_DEFINED
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +0100624 case MMC_TIMING_MMC_DDR52:
625 timing = GB_SDIO_TIMING_MMC_DDR52;
626 break;
Rui Miguel Silva5656ab92015-06-24 23:20:26 +0100627#endif
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +0100628 case MMC_TIMING_MMC_HS200:
629 timing = GB_SDIO_TIMING_MMC_HS200;
630 break;
Rui Miguel Silva5656ab92015-06-24 23:20:26 +0100631#ifdef MMC_HS400_SUPPORTED
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +0100632 case MMC_TIMING_MMC_HS400:
633 timing = GB_SDIO_TIMING_MMC_HS400;
634 break;
Rui Miguel Silva5656ab92015-06-24 23:20:26 +0100635#endif
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +0100636 }
637 request.timing = timing;
638
639 switch (ios->signal_voltage) {
640 case MMC_SIGNAL_VOLTAGE_330:
641 signal_voltage = GB_SDIO_SIGNAL_VOLTAGE_330;
642 break;
643 case MMC_SIGNAL_VOLTAGE_180:
644 default:
645 signal_voltage = GB_SDIO_SIGNAL_VOLTAGE_180;
646 break;
647 case MMC_SIGNAL_VOLTAGE_120:
648 signal_voltage = GB_SDIO_SIGNAL_VOLTAGE_120;
649 break;
650 }
651 request.signal_voltage = signal_voltage;
652
653 switch (ios->drv_type) {
654 case MMC_SET_DRIVER_TYPE_A:
655 drv_type = GB_SDIO_SET_DRIVER_TYPE_A;
656 break;
657 case MMC_SET_DRIVER_TYPE_C:
658 drv_type = GB_SDIO_SET_DRIVER_TYPE_C;
659 break;
660 case MMC_SET_DRIVER_TYPE_D:
661 drv_type = GB_SDIO_SET_DRIVER_TYPE_D;
662 break;
663 case MMC_SET_DRIVER_TYPE_B:
664 default:
665 drv_type = GB_SDIO_SET_DRIVER_TYPE_B;
666 break;
667 }
668 request.drv_type = drv_type;
669
670 ret = gb_sdio_set_ios(host, &request);
671 if (ret < 0)
672 goto out;
673
674 memcpy(&mmc->ios, ios, sizeof(mmc->ios));
675
676out:
677 mutex_unlock(&host->lock);
678}
679
680static int gb_mmc_get_ro(struct mmc_host *mmc)
681{
682 struct gb_sdio_host *host = mmc_priv(mmc);
683
684 mutex_lock(&host->lock);
685 if (host->removed)
686 return -ESHUTDOWN;
687 mutex_unlock(&host->lock);
Rui Miguel Silva08ccc9b2015-07-02 19:11:32 +0100688 return host->read_only;
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +0100689}
690
691static int gb_mmc_get_cd(struct mmc_host *mmc)
692{
693 struct gb_sdio_host *host = mmc_priv(mmc);
694
695 mutex_lock(&host->lock);
696 if (host->removed)
697 return -ESHUTDOWN;
698 mutex_unlock(&host->lock);
Rui Miguel Silva08ccc9b2015-07-02 19:11:32 +0100699 return host->card_present;
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +0100700}
701
702static const struct mmc_host_ops gb_sdio_ops = {
703 .request = gb_mmc_request,
704 .set_ios = gb_mmc_set_ios,
705 .get_ro = gb_mmc_get_ro,
706 .get_cd = gb_mmc_get_cd,
Greg Kroah-Hartman83ddaaa2014-08-11 17:27:22 +0800707};
708
Greg Kroah-Hartmana2f47632014-10-28 10:17:09 +0800709static int gb_sdio_connection_init(struct gb_connection *connection)
Greg Kroah-Hartman83ddaaa2014-08-11 17:27:22 +0800710{
711 struct mmc_host *mmc;
Greg Kroah-Hartman199d68d2014-08-30 16:20:22 -0700712 struct gb_sdio_host *host;
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +0100713 size_t max_buffer;
714 int ret = 0;
Greg Kroah-Hartman83ddaaa2014-08-11 17:27:22 +0800715
Greg Kroah-Hartman61c80572015-10-14 11:19:42 -0700716 mmc = mmc_alloc_host(sizeof(*host), &connection->bundle->dev);
Greg Kroah-Hartman83ddaaa2014-08-11 17:27:22 +0800717 if (!mmc)
718 return -ENOMEM;
719
720 host = mmc_priv(mmc);
721 host->mmc = mmc;
Rui Miguel Silvac36d31c2015-07-02 19:11:31 +0100722 host->removed = true;
Greg Kroah-Hartman83ddaaa2014-08-11 17:27:22 +0800723
Greg Kroah-Hartmana2f47632014-10-28 10:17:09 +0800724 host->connection = connection;
725 connection->private = host;
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +0100726
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +0100727 ret = gb_sdio_get_caps(host);
728 if (ret < 0)
729 goto free_mmc;
730
731 mmc->ops = &gb_sdio_ops;
732
733 /* for now we just make a map 1:1 between max blocks and segments */
734 mmc->max_segs = host->mmc->max_blk_count;
735 mmc->max_seg_size = host->mmc->max_blk_size;
736
737 mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
738
739 max_buffer = gb_operation_get_payload_size_max(host->connection);
740 host->xfer_buffer = kzalloc(max_buffer, GFP_KERNEL);
741 if (!host->xfer_buffer) {
742 ret = -ENOMEM;
743 goto free_mmc;
744 }
745 mutex_init(&host->lock);
746 spin_lock_init(&host->xfer);
Johan Hovoldb9154df2015-09-14 20:19:04 +0200747 host->mrq_workqueue = alloc_workqueue("mmc-%s", 0, 1,
Greg Kroah-Hartman61c80572015-10-14 11:19:42 -0700748 dev_name(&connection->bundle->dev));
Johan Hovoldb9154df2015-09-14 20:19:04 +0200749 if (!host->mrq_workqueue) {
750 ret = -ENOMEM;
751 goto free_buffer;
752 }
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +0100753 INIT_WORK(&host->mrqwork, gb_sdio_mrq_work);
754
755 ret = mmc_add_host(mmc);
756 if (ret < 0)
757 goto free_work;
Rui Miguel Silvac36d31c2015-07-02 19:11:31 +0100758 host->removed = false;
759 ret = _gb_sdio_process_events(host, host->queued_events);
760 host->queued_events = 0;
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +0100761
762 return ret;
763
764free_work:
Johan Hovoldb9154df2015-09-14 20:19:04 +0200765 destroy_workqueue(host->mrq_workqueue);
766free_buffer:
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +0100767 kfree(host->xfer_buffer);
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +0100768free_mmc:
769 connection->private = NULL;
770 mmc_free_host(mmc);
771
772 return ret;
Greg Kroah-Hartman83ddaaa2014-08-11 17:27:22 +0800773}
774
Greg Kroah-Hartmana2f47632014-10-28 10:17:09 +0800775static void gb_sdio_connection_exit(struct gb_connection *connection)
Greg Kroah-Hartman83ddaaa2014-08-11 17:27:22 +0800776{
777 struct mmc_host *mmc;
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +0100778 struct gb_sdio_host *host = connection->private;
Greg Kroah-Hartman83ddaaa2014-08-11 17:27:22 +0800779
Alex Elder051fb042014-10-16 06:35:24 -0500780 if (!host)
781 return;
Greg Kroah-Hartman83ddaaa2014-08-11 17:27:22 +0800782
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +0100783 mutex_lock(&host->lock);
784 host->removed = true;
Alex Elder051fb042014-10-16 06:35:24 -0500785 mmc = host->mmc;
Greg Kroah-Hartmana2f47632014-10-28 10:17:09 +0800786 connection->private = NULL;
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +0100787 mutex_unlock(&host->lock);
788
Johan Hovoldb9154df2015-09-14 20:19:04 +0200789 flush_workqueue(host->mrq_workqueue);
790 destroy_workqueue(host->mrq_workqueue);
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +0100791 mmc_remove_host(mmc);
792 kfree(host->xfer_buffer);
Johan Hovolde5265262015-09-14 20:19:03 +0200793 mmc_free_host(mmc);
Greg Kroah-Hartman83ddaaa2014-08-11 17:27:22 +0800794}
795
Alex Elder19d03de2014-11-05 16:12:53 -0600796static struct gb_protocol sdio_protocol = {
Greg Kroah-Hartman7422a1e2014-12-24 13:01:45 -0800797 .name = "sdio",
Alex Elder19d03de2014-11-05 16:12:53 -0600798 .id = GREYBUS_PROTOCOL_SDIO,
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +0100799 .major = GB_SDIO_VERSION_MAJOR,
800 .minor = GB_SDIO_VERSION_MINOR,
Alex Elder5d9fd7e2014-11-05 16:12:54 -0600801 .connection_init = gb_sdio_connection_init,
802 .connection_exit = gb_sdio_connection_exit,
Rui Miguel Silva3b6ecd62015-06-22 14:03:52 +0100803 .request_recv = gb_sdio_event_recv,
Alex Elder19d03de2014-11-05 16:12:53 -0600804};
805
Viresh Kumare18822e2015-07-01 12:13:52 +0530806gb_builtin_protocol_driver(sdio_protocol);