Linux Kernel
3.7.1
Main Page
Related Pages
Modules
Namespaces
Data Structures
Files
File List
Globals
All
Data Structures
Namespaces
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Macros
Groups
Pages
drivers
media
mmc
siano
smssdio.c
Go to the documentation of this file.
1
/*
2
* smssdio.c - Siano 1xxx SDIO interface driver
3
*
4
* Copyright 2008 Pierre Ossman
5
*
6
* Based on code by Siano Mobile Silicon, Inc.,
7
* Copyright (C) 2006-2008, Uri Shkolnik
8
*
9
* This program is free software; you can redistribute it and/or modify
10
* it under the terms of the GNU General Public License as published by
11
* the Free Software Foundation; either version 2 of the License, or (at
12
* your option) any later version.
13
*
14
*
15
* This hardware is a bit odd in that all transfers should be done
16
* to/from the SMSSDIO_DATA register, yet the "increase address" bit
17
* always needs to be set.
18
*
19
* Also, buffers from the card are always aligned to 128 byte
20
* boundaries.
21
*/
22
23
/*
24
* General cleanup notes:
25
*
26
* - only typedefs should be name *_t
27
*
28
* - use ERR_PTR and friends for smscore_register_device()
29
*
30
* - smscore_getbuffer should zero fields
31
*
32
* Fix stop command
33
*/
34
35
#include <
linux/moduleparam.h
>
36
#include <linux/slab.h>
37
#include <
linux/firmware.h
>
38
#include <
linux/delay.h
>
39
#include <
linux/mmc/card.h
>
40
#include <
linux/mmc/sdio_func.h
>
41
#include <
linux/mmc/sdio_ids.h
>
42
#include <linux/module.h>
43
44
#include "
smscoreapi.h
"
45
#include "
sms-cards.h
"
46
47
/* Registers */
48
49
#define SMSSDIO_DATA 0x00
50
#define SMSSDIO_INT 0x04
51
#define SMSSDIO_BLOCK_SIZE 128
52
53
static
const
struct
sdio_device_id
smssdio_ids[]
__devinitconst
= {
54
{
SDIO_DEVICE
(
SDIO_VENDOR_ID_SIANO
,
SDIO_DEVICE_ID_SIANO_STELLAR
),
55
.driver_data =
SMS1XXX_BOARD_SIANO_STELLAR
},
56
{
SDIO_DEVICE
(
SDIO_VENDOR_ID_SIANO
,
SDIO_DEVICE_ID_SIANO_NOVA_A0
),
57
.driver_data =
SMS1XXX_BOARD_SIANO_NOVA_A
},
58
{
SDIO_DEVICE
(
SDIO_VENDOR_ID_SIANO
,
SDIO_DEVICE_ID_SIANO_NOVA_B0
),
59
.driver_data =
SMS1XXX_BOARD_SIANO_NOVA_B
},
60
{
SDIO_DEVICE
(
SDIO_VENDOR_ID_SIANO
,
SDIO_DEVICE_ID_SIANO_VEGA_A0
),
61
.driver_data =
SMS1XXX_BOARD_SIANO_VEGA
},
62
{
SDIO_DEVICE
(
SDIO_VENDOR_ID_SIANO
,
SDIO_DEVICE_ID_SIANO_VENICE
),
63
.driver_data =
SMS1XXX_BOARD_SIANO_VEGA
},
64
{
/* end: all zeroes */
},
65
};
66
67
MODULE_DEVICE_TABLE
(sdio, smssdio_ids);
68
69
struct
smssdio_device
{
70
struct
sdio_func
*
func
;
71
72
struct
smscore_device_t
*
coredev
;
73
74
struct
smscore_buffer_t
*
split_cb
;
75
};
76
77
/*******************************************************************/
78
/* Siano core callbacks */
79
/*******************************************************************/
80
81
static
int
smssdio_sendrequest(
void
*
context
,
void
*
buffer
,
size_t
size
)
82
{
83
int
ret
= 0;
84
struct
smssdio_device
*smsdev;
85
86
smsdev =
context
;
87
88
sdio_claim_host
(smsdev->
func
);
89
90
while
(size >= smsdev->
func
->cur_blksize) {
91
ret =
sdio_memcpy_toio
(smsdev->
func
,
SMSSDIO_DATA
,
92
buffer, smsdev->
func
->cur_blksize);
93
if
(ret)
94
goto
out
;
95
96
buffer += smsdev->
func
->cur_blksize;
97
size -= smsdev->
func
->cur_blksize;
98
}
99
100
if
(size) {
101
ret =
sdio_memcpy_toio
(smsdev->
func
,
SMSSDIO_DATA
,
102
buffer, size);
103
}
104
105
out
:
106
sdio_release_host
(smsdev->
func
);
107
108
return
ret
;
109
}
110
111
/*******************************************************************/
112
/* SDIO callbacks */
113
/*******************************************************************/
114
115
static
void
smssdio_interrupt(
struct
sdio_func
*
func
)
116
{
117
int
ret
;
118
119
struct
smssdio_device
*smsdev;
120
struct
smscore_buffer_t
*
cb
;
121
struct
SmsMsgHdr_ST
*
hdr
;
122
size_t
size
;
123
124
smsdev =
sdio_get_drvdata
(func);
125
126
/*
127
* The interrupt register has no defined meaning. It is just
128
* a way of turning of the level triggered interrupt.
129
*/
130
(
void
)
sdio_readb
(func,
SMSSDIO_INT
, &ret);
131
if
(ret) {
132
sms_err
(
"Unable to read interrupt register!\n"
);
133
return
;
134
}
135
136
if
(smsdev->
split_cb
==
NULL
) {
137
cb =
smscore_getbuffer
(smsdev->
coredev
);
138
if
(!cb) {
139
sms_err
(
"Unable to allocate data buffer!\n"
);
140
return
;
141
}
142
143
ret =
sdio_memcpy_fromio
(smsdev->
func
,
144
cb->
p
,
145
SMSSDIO_DATA
,
146
SMSSDIO_BLOCK_SIZE
);
147
if
(ret) {
148
sms_err
(
"Error %d reading initial block!\n"
, ret);
149
return
;
150
}
151
152
hdr = cb->
p
;
153
154
if
(hdr->
msgFlags
&
MSG_HDR_FLAG_SPLIT_MSG
) {
155
smsdev->
split_cb
= cb;
156
return
;
157
}
158
159
if
(hdr->
msgLength
> smsdev->
func
->cur_blksize)
160
size = hdr->
msgLength
- smsdev->
func
->cur_blksize;
161
else
162
size = 0;
163
}
else
{
164
cb = smsdev->
split_cb
;
165
hdr = cb->
p
;
166
167
size = hdr->
msgLength
-
sizeof
(
struct
SmsMsgHdr_ST
);
168
169
smsdev->
split_cb
=
NULL
;
170
}
171
172
if
(size) {
173
void
*
buffer
;
174
175
buffer = cb->
p
+ (hdr->
msgLength
-
size
);
176
size =
ALIGN
(size,
SMSSDIO_BLOCK_SIZE
);
177
178
BUG_ON
(smsdev->
func
->cur_blksize !=
SMSSDIO_BLOCK_SIZE
);
179
180
/*
181
* First attempt to transfer all of it in one go...
182
*/
183
ret =
sdio_memcpy_fromio
(smsdev->
func
,
184
buffer,
185
SMSSDIO_DATA
,
186
size);
187
if
(ret && ret != -
EINVAL
) {
188
smscore_putbuffer
(smsdev->
coredev
, cb);
189
sms_err
(
"Error %d reading data from card!\n"
, ret);
190
return
;
191
}
192
193
/*
194
* ..then fall back to one block at a time if that is
195
* not possible...
196
*
197
* (we have to do this manually because of the
198
* problem with the "increase address" bit)
199
*/
200
if
(ret == -
EINVAL
) {
201
while
(size) {
202
ret =
sdio_memcpy_fromio
(smsdev->
func
,
203
buffer,
SMSSDIO_DATA
,
204
smsdev->
func
->cur_blksize);
205
if
(ret) {
206
smscore_putbuffer
(smsdev->
coredev
, cb);
207
sms_err
(
"Error %d reading "
208
"data from card!\n"
, ret);
209
return
;
210
}
211
212
buffer += smsdev->
func
->cur_blksize;
213
if
(size > smsdev->
func
->cur_blksize)
214
size -= smsdev->
func
->cur_blksize;
215
else
216
size = 0;
217
}
218
}
219
}
220
221
cb->
size
= hdr->
msgLength
;
222
cb->
offset
= 0;
223
224
smscore_onresponse
(smsdev->
coredev
, cb);
225
}
226
227
static
int
__devinit
smssdio_probe(
struct
sdio_func
*func,
228
const
struct
sdio_device_id
*
id
)
229
{
230
int
ret
;
231
232
int
board_id
;
233
struct
smssdio_device
*smsdev;
234
struct
smsdevice_params_t
params
;
235
236
board_id =
id
->driver_data;
237
238
smsdev = kzalloc(
sizeof
(
struct
smssdio_device
),
GFP_KERNEL
);
239
if
(!smsdev)
240
return
-
ENOMEM
;
241
242
smsdev->
func
=
func
;
243
244
memset
(&
params
, 0,
sizeof
(
struct
smsdevice_params_t
));
245
246
params
.device = &func->
dev
;
247
params
.buffer_size = 0x5000;
/* ?? */
248
params
.num_buffers = 22;
/* ?? */
249
params
.context = smsdev;
250
251
snprintf
(
params
.devpath,
sizeof
(
params
.devpath),
252
"sdio\\%s"
,
sdio_func_id
(func));
253
254
params
.sendrequest_handler = smssdio_sendrequest;
255
256
params
.device_type =
sms_get_board
(board_id)->type;
257
258
if
(
params
.device_type !=
SMS_STELLAR
)
259
params
.flags |=
SMS_DEVICE_FAMILY2
;
260
else
{
261
/*
262
* FIXME: Stellar needs special handling...
263
*/
264
ret = -
ENODEV
;
265
goto
free
;
266
}
267
268
ret =
smscore_register_device
(&
params
, &smsdev->
coredev
);
269
if
(ret < 0)
270
goto
free
;
271
272
smscore_set_board_id
(smsdev->
coredev
, board_id);
273
274
sdio_claim_host
(func);
275
276
ret =
sdio_enable_func
(func);
277
if
(ret)
278
goto
release
;
279
280
ret =
sdio_set_block_size
(func,
SMSSDIO_BLOCK_SIZE
);
281
if
(ret)
282
goto
disable
;
283
284
ret =
sdio_claim_irq
(func, smssdio_interrupt);
285
if
(ret)
286
goto
disable
;
287
288
sdio_set_drvdata
(func, smsdev);
289
290
sdio_release_host
(func);
291
292
ret =
smscore_start_device
(smsdev->
coredev
);
293
if
(ret < 0)
294
goto
reclaim
;
295
296
return
0;
297
298
reclaim
:
299
sdio_claim_host
(func);
300
sdio_release_irq
(func);
301
disable
:
302
sdio_disable_func
(func);
303
release
:
304
sdio_release_host
(func);
305
smscore_unregister_device
(smsdev->
coredev
);
306
free
:
307
kfree
(smsdev);
308
309
return
ret
;
310
}
311
312
static
void
smssdio_remove(
struct
sdio_func
*func)
313
{
314
struct
smssdio_device
*smsdev;
315
316
smsdev =
sdio_get_drvdata
(func);
317
318
/* FIXME: racy! */
319
if
(smsdev->
split_cb
)
320
smscore_putbuffer
(smsdev->
coredev
, smsdev->
split_cb
);
321
322
smscore_unregister_device
(smsdev->
coredev
);
323
324
sdio_claim_host
(func);
325
sdio_release_irq
(func);
326
sdio_disable_func
(func);
327
sdio_release_host
(func);
328
329
kfree
(smsdev);
330
}
331
332
static
struct
sdio_driver
smssdio_driver = {
333
.name =
"smssdio"
,
334
.id_table = smssdio_ids,
335
.probe = smssdio_probe,
336
.remove = smssdio_remove,
337
};
338
339
/*******************************************************************/
340
/* Module functions */
341
/*******************************************************************/
342
343
static
int
__init
smssdio_module_init(
void
)
344
{
345
int
ret = 0;
346
347
printk
(
KERN_INFO
"smssdio: Siano SMS1xxx SDIO driver\n"
);
348
printk
(
KERN_INFO
"smssdio: Copyright Pierre Ossman\n"
);
349
350
ret =
sdio_register_driver
(&smssdio_driver);
351
352
return
ret
;
353
}
354
355
static
void
__exit
smssdio_module_exit(
void
)
356
{
357
sdio_unregister_driver
(&smssdio_driver);
358
}
359
360
module_init
(smssdio_module_init);
361
module_exit
(smssdio_module_exit);
362
363
MODULE_DESCRIPTION
(
"Siano SMS1xxx SDIO driver"
);
364
MODULE_AUTHOR
(
"Pierre Ossman"
);
365
MODULE_LICENSE
(
"GPL"
);
Generated on Thu Jan 10 2013 13:47:04 for Linux Kernel by
1.8.2