2 * NAND flash driver for Broadcom Secondary Memory Interface
4 * Written by Luke Wren <luke@raspberrypi.org>
5 * Copyright (c) 2015, Raspberry Pi (Trading) Ltd.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions, and the following disclaimer,
12 * without modification.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. The names of the above-listed copyright holders may not be used
17 * to endorse or promote products derived from this software without
18 * specific prior written permission.
20 * ALTERNATIVELY, this software may be distributed under the terms of the
21 * GNU General Public License ("GPL") version 2, as published by the Free
22 * Software Foundation.
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
25 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
26 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
27 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
28 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
29 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
30 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
31 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
32 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
33 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
34 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 #include <linux/kernel.h>
38 #include <linux/module.h>
40 #include <linux/platform_device.h>
41 #include <linux/slab.h>
42 #include <linux/mtd/nand.h>
43 #include <linux/mtd/partitions.h>
45 #include <linux/broadcom/bcm2835_smi.h>
47 #define DEVICE_NAME "bcm2835-smi-nand"
48 #define DRIVER_NAME "smi-nand-bcm2835"
50 struct bcm2835_smi_nand_host
{
51 struct bcm2835_smi_instance
*smi_inst
;
52 struct nand_chip nand_chip
;
57 /****************************************************************************
59 * NAND functionality implementation
61 ****************************************************************************/
63 #define SMI_NAND_CLE_PIN 0x01
64 #define SMI_NAND_ALE_PIN 0x02
66 static inline void bcm2835_smi_nand_cmd_ctrl(struct mtd_info
*mtd
, int cmd
,
70 uint32_t addr
= ~(SMI_NAND_CLE_PIN
| SMI_NAND_ALE_PIN
);
71 struct bcm2835_smi_nand_host
*host
= dev_get_drvdata(mtd
->dev
.parent
);
72 struct bcm2835_smi_instance
*inst
= host
->smi_inst
;
75 addr
|= SMI_NAND_CLE_PIN
;
77 addr
|= SMI_NAND_ALE_PIN
;
78 /* Lower ALL the CS pins! */
80 addr
&= (SMI_NAND_CLE_PIN
| SMI_NAND_ALE_PIN
);
82 bcm2835_smi_set_address(inst
, addr
);
84 if (cmd
!= NAND_CMD_NONE
)
85 bcm2835_smi_write_buf(inst
, &cmd32
, 1);
88 static inline uint8_t bcm2835_smi_nand_read_byte(struct mtd_info
*mtd
)
91 struct bcm2835_smi_nand_host
*host
= dev_get_drvdata(mtd
->dev
.parent
);
92 struct bcm2835_smi_instance
*inst
= host
->smi_inst
;
94 bcm2835_smi_read_buf(inst
, &byte
, 1);
98 static inline void bcm2835_smi_nand_write_byte(struct mtd_info
*mtd
,
101 struct bcm2835_smi_nand_host
*host
= dev_get_drvdata(mtd
->dev
.parent
);
102 struct bcm2835_smi_instance
*inst
= host
->smi_inst
;
104 bcm2835_smi_write_buf(inst
, &byte
, 1);
107 static inline void bcm2835_smi_nand_write_buf(struct mtd_info
*mtd
,
108 const uint8_t *buf
, int len
)
110 struct bcm2835_smi_nand_host
*host
= dev_get_drvdata(mtd
->dev
.parent
);
111 struct bcm2835_smi_instance
*inst
= host
->smi_inst
;
113 bcm2835_smi_write_buf(inst
, buf
, len
);
116 static inline void bcm2835_smi_nand_read_buf(struct mtd_info
*mtd
,
117 uint8_t *buf
, int len
)
119 struct bcm2835_smi_nand_host
*host
= dev_get_drvdata(mtd
->dev
.parent
);
120 struct bcm2835_smi_instance
*inst
= host
->smi_inst
;
122 bcm2835_smi_read_buf(inst
, buf
, len
);
125 /****************************************************************************
127 * Probe and remove functions
129 ***************************************************************************/
131 static int bcm2835_smi_nand_probe(struct platform_device
*pdev
)
133 struct bcm2835_smi_nand_host
*host
;
134 struct nand_chip
*this;
135 struct mtd_info
*mtd
;
136 struct device
*dev
= &pdev
->dev
;
137 struct device_node
*node
= dev
->of_node
, *smi_node
;
138 struct mtd_part_parser_data ppdata
;
139 struct smi_settings
*smi_settings
;
140 struct bcm2835_smi_instance
*smi_inst
;
144 dev_err(dev
, "No device tree node supplied!");
148 smi_node
= of_parse_phandle(node
, "smi_handle", 0);
150 /* Request use of SMI peripheral: */
151 smi_inst
= bcm2835_smi_get(smi_node
);
154 dev_err(dev
, "Could not register with SMI.");
155 return -EPROBE_DEFER
;
158 /* Set SMI timing and bus width */
160 smi_settings
= bcm2835_smi_get_settings_from_regs(smi_inst
);
162 smi_settings
->data_width
= SMI_WIDTH_8BIT
;
163 smi_settings
->read_setup_time
= 2;
164 smi_settings
->read_hold_time
= 1;
165 smi_settings
->read_pace_time
= 1;
166 smi_settings
->read_strobe_time
= 3;
168 smi_settings
->write_setup_time
= 2;
169 smi_settings
->write_hold_time
= 1;
170 smi_settings
->write_pace_time
= 1;
171 smi_settings
->write_strobe_time
= 3;
173 bcm2835_smi_set_regs_from_settings(smi_inst
);
175 host
= devm_kzalloc(dev
, sizeof(struct bcm2835_smi_nand_host
),
181 host
->smi_inst
= smi_inst
;
183 platform_set_drvdata(pdev
, host
);
185 /* Link the structures together */
187 this = &host
->nand_chip
;
190 mtd
->owner
= THIS_MODULE
;
191 mtd
->dev
.parent
= dev
;
192 mtd
->name
= DRIVER_NAME
;
194 /* 20 us command delay time... */
195 this->chip_delay
= 20;
198 this->cmd_ctrl
= bcm2835_smi_nand_cmd_ctrl
;
199 this->read_byte
= bcm2835_smi_nand_read_byte
;
200 this->write_byte
= bcm2835_smi_nand_write_byte
;
201 this->write_buf
= bcm2835_smi_nand_write_buf
;
202 this->read_buf
= bcm2835_smi_nand_read_buf
;
204 this->ecc
.mode
= NAND_ECC_SOFT
;
206 /* Should never be accessed directly: */
208 this->IO_ADDR_R
= (void *)0xdeadbeef;
209 this->IO_ADDR_W
= (void *)0xdeadbeef;
211 /* First scan to find the device and get the page size */
213 if (nand_scan_ident(mtd
, 1, NULL
))
216 /* Second phase scan */
218 if (nand_scan_tail(mtd
))
221 ret
= mtd_device_parse_register(mtd
, NULL
, &ppdata
, NULL
, 0);
229 static int bcm2835_smi_nand_remove(struct platform_device
*pdev
)
231 struct bcm2835_smi_nand_host
*host
= platform_get_drvdata(pdev
);
233 nand_release(&host
->mtd
);
238 /****************************************************************************
240 * Register the driver with device tree
242 ***************************************************************************/
244 static const struct of_device_id bcm2835_smi_nand_of_match
[] = {
245 {.compatible
= "brcm,bcm2835-smi-nand",},
249 MODULE_DEVICE_TABLE(of
, bcm2835_smi_nand_of_match
);
251 static struct platform_driver bcm2835_smi_nand_driver
= {
252 .probe
= bcm2835_smi_nand_probe
,
253 .remove
= bcm2835_smi_nand_remove
,
256 .owner
= THIS_MODULE
,
257 .of_match_table
= bcm2835_smi_nand_of_match
,
261 module_platform_driver(bcm2835_smi_nand_driver
);
263 MODULE_ALIAS("platform:smi-nand-bcm2835");
264 MODULE_LICENSE("GPL");
266 ("Driver for NAND chips using Broadcom Secondary Memory Interface");
267 MODULE_AUTHOR("Luke Wren <luke@raspberrypi.org>");