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
mtd
nand
pasemi_nand.c
Go to the documentation of this file.
1
/*
2
* Copyright (C) 2006-2007 PA Semi, Inc
3
*
4
* Author: Egor Martovetsky <
[email protected]
>
5
* Maintained by: Olof Johansson <
[email protected]
>
6
*
7
* Driver for the PWRficient onchip NAND flash interface
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 version 2 as
11
* published by the Free Software Foundation.
12
*
13
* This program is distributed in the hope that it will be useful,
14
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
* GNU General Public License for more details.
17
*
18
* You should have received a copy of the GNU General Public License
19
* along with this program; if not, write to the Free Software
20
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21
*/
22
23
#undef DEBUG
24
25
#include <linux/slab.h>
26
#include <
linux/init.h
>
27
#include <linux/module.h>
28
#include <
linux/mtd/mtd.h
>
29
#include <
linux/mtd/nand.h
>
30
#include <
linux/mtd/nand_ecc.h
>
31
#include <
linux/of_platform.h
>
32
#include <
linux/platform_device.h
>
33
#include <linux/pci.h>
34
35
#include <asm/io.h>
36
37
#define LBICTRL_LPCCTL_NR 0x00004000
38
#define CLE_PIN_CTL 15
39
#define ALE_PIN_CTL 14
40
41
static
unsigned
int
lpcctl;
42
static
struct
mtd_info
*pasemi_nand_mtd;
43
static
const
char
driver_name
[] =
"pasemi-nand"
;
44
45
static
void
pasemi_read_buf(
struct
mtd_info
*mtd,
u_char
*
buf
,
int
len)
46
{
47
struct
nand_chip
*
chip
= mtd->
priv
;
48
49
while
(len > 0x800) {
50
memcpy_fromio
(buf, chip->
IO_ADDR_R
, 0x800);
51
buf += 0x800;
52
len -= 0x800;
53
}
54
memcpy_fromio
(buf, chip->
IO_ADDR_R
, len);
55
}
56
57
static
void
pasemi_write_buf(
struct
mtd_info
*mtd,
const
u_char
*
buf
,
int
len)
58
{
59
struct
nand_chip
*
chip
= mtd->
priv
;
60
61
while
(len > 0x800) {
62
memcpy_toio
(chip->
IO_ADDR_R
, buf, 0x800);
63
buf += 0x800;
64
len -= 0x800;
65
}
66
memcpy_toio
(chip->
IO_ADDR_R
, buf, len);
67
}
68
69
static
void
pasemi_hwcontrol(
struct
mtd_info
*mtd,
int
cmd
,
70
unsigned
int
ctrl
)
71
{
72
struct
nand_chip
*chip = mtd->
priv
;
73
74
if
(cmd ==
NAND_CMD_NONE
)
75
return
;
76
77
if
(ctrl &
NAND_CLE
)
78
out_8
(chip->
IO_ADDR_W
+ (1 <<
CLE_PIN_CTL
), cmd);
79
else
80
out_8
(chip->
IO_ADDR_W
+ (1 <<
ALE_PIN_CTL
), cmd);
81
82
/* Push out posted writes */
83
eieio
();
84
inl
(lpcctl);
85
}
86
87
int
pasemi_device_ready
(
struct
mtd_info
*mtd)
88
{
89
return
!!(
inl
(lpcctl) &
LBICTRL_LPCCTL_NR
);
90
}
91
92
static
int
__devinit
pasemi_nand_probe(
struct
platform_device
*ofdev)
93
{
94
struct
pci_dev
*
pdev
;
95
struct
device_node
*np = ofdev->
dev
.of_node;
96
struct
resource
res
;
97
struct
nand_chip
*
chip
;
98
int
err
= 0;
99
100
err =
of_address_to_resource
(np, 0, &
res
);
101
102
if
(err)
103
return
-
EINVAL
;
104
105
/* We only support one device at the moment */
106
if
(pasemi_nand_mtd)
107
return
-
ENODEV
;
108
109
pr_debug
(
"pasemi_nand at %pR\n"
, &
res
);
110
111
/* Allocate memory for MTD device structure and private data */
112
pasemi_nand_mtd = kzalloc(
sizeof
(
struct
mtd_info
) +
113
sizeof
(
struct
nand_chip
),
GFP_KERNEL
);
114
if
(!pasemi_nand_mtd) {
115
printk
(
KERN_WARNING
116
"Unable to allocate PASEMI NAND MTD device structure\n"
);
117
err = -
ENOMEM
;
118
goto
out
;
119
}
120
121
/* Get pointer to private data */
122
chip = (
struct
nand_chip
*)&pasemi_nand_mtd[1];
123
124
/* Link the private data with the MTD structure */
125
pasemi_nand_mtd->
priv
=
chip
;
126
pasemi_nand_mtd->
owner
=
THIS_MODULE
;
127
128
chip->
IO_ADDR_R
=
of_iomap
(np, 0);
129
chip->
IO_ADDR_W
= chip->
IO_ADDR_R
;
130
131
if
(!chip->
IO_ADDR_R
) {
132
err = -
EIO
;
133
goto
out_mtd;
134
}
135
136
pdev =
pci_get_device
(
PCI_VENDOR_ID_PASEMI
, 0xa008,
NULL
);
137
if
(!pdev) {
138
err = -
ENODEV
;
139
goto
out_ior;
140
}
141
142
lpcctl =
pci_resource_start
(pdev, 0);
143
pci_dev_put
(pdev);
144
145
if
(!
request_region
(lpcctl, 4,
driver_name
)) {
146
err = -
EBUSY
;
147
goto
out_ior;
148
}
149
150
chip->
cmd_ctrl
= pasemi_hwcontrol;
151
chip->
dev_ready
=
pasemi_device_ready
;
152
chip->
read_buf
= pasemi_read_buf;
153
chip->
write_buf
= pasemi_write_buf;
154
chip->
chip_delay
= 0;
155
chip->
ecc
.mode =
NAND_ECC_SOFT
;
156
157
/* Enable the following for a flash based bad block table */
158
chip->
bbt_options
=
NAND_BBT_USE_FLASH
;
159
160
/* Scan to find existence of the device */
161
if
(
nand_scan
(pasemi_nand_mtd, 1)) {
162
err = -
ENXIO
;
163
goto
out_lpc;
164
}
165
166
if
(
mtd_device_register
(pasemi_nand_mtd,
NULL
, 0)) {
167
printk
(
KERN_ERR
"pasemi_nand: Unable to register MTD device\n"
);
168
err = -
ENODEV
;
169
goto
out_lpc;
170
}
171
172
printk
(
KERN_INFO
"PA Semi NAND flash at %08llx, control at I/O %x\n"
,
173
res
.start, lpcctl);
174
175
return
0;
176
177
out_lpc:
178
release_region
(lpcctl, 4);
179
out_ior:
180
iounmap
(chip->
IO_ADDR_R
);
181
out_mtd:
182
kfree
(pasemi_nand_mtd);
183
out
:
184
return
err
;
185
}
186
187
static
int
__devexit
pasemi_nand_remove(
struct
platform_device
*ofdev)
188
{
189
struct
nand_chip
*
chip
;
190
191
if
(!pasemi_nand_mtd)
192
return
0;
193
194
chip = pasemi_nand_mtd->
priv
;
195
196
/* Release resources, unregister device */
197
nand_release
(pasemi_nand_mtd);
198
199
release_region
(lpcctl, 4);
200
201
iounmap
(chip->
IO_ADDR_R
);
202
203
/* Free the MTD device structure */
204
kfree
(pasemi_nand_mtd);
205
206
pasemi_nand_mtd =
NULL
;
207
208
return
0;
209
}
210
211
static
const
struct
of_device_id
pasemi_nand_match[] =
212
{
213
{
214
.compatible =
"pasemi,localbus-nand"
,
215
},
216
{},
217
};
218
219
MODULE_DEVICE_TABLE
(of, pasemi_nand_match);
220
221
static
struct
platform_driver
pasemi_nand_driver =
222
{
223
.driver = {
224
.name = (
char
*)
driver_name
,
225
.
owner
=
THIS_MODULE
,
226
.of_match_table = pasemi_nand_match,
227
},
228
.
probe
= pasemi_nand_probe,
229
.
remove
= pasemi_nand_remove,
230
};
231
232
module_platform_driver
(pasemi_nand_driver);
233
234
MODULE_LICENSE
(
"GPL"
);
235
MODULE_AUTHOR
(
"Egor Martovetsky <
[email protected]
>"
);
236
MODULE_DESCRIPTION
(
"NAND flash interface driver for PA Semi PWRficient"
);
Generated on Thu Jan 10 2013 13:57:03 for Linux Kernel by
1.8.2