@@ -23,6 +23,8 @@
#include <linux/platform_data/usb-ohci-pxa27x.h>
#include <linux/platform_data/mmc-pxamci.h>
+#include <linux/mtd/platnand.h>
+
#include "generic.h"
/* physical address if local-bus attached devices */
@@ -36,6 +38,10 @@
/* MMC power enable */
#define GPIO105_MMC_POWER (105)
+/* NAND GPIOs */
+#define GPIO11_NAND_CS (11)
+#define GPIO89_NAND_RB (89)
+
/* WLAN GPIOS */
#define GPIO19_WLAN_STRAP (19)
#define GPIO102_WLAN_RST (102)
@@ -309,6 +315,130 @@ static void __init cmx270_init_mmc(void)
static inline void cmx270_init_mmc(void) {}
#endif
+/* NAND flash */
+#if IS_ENABLED(CONFIG_MTD_NAND_PLATFORM)
+static inline void nand_cs_on(void)
+{
+ gpio_set_value(GPIO11_NAND_CS, 0);
+}
+
+static void nand_cs_off(void)
+{
+ dsb();
+
+ gpio_set_value(GPIO11_NAND_CS, 1);
+}
+
+/* hardware specific access to control-lines */
+static void cmx270_nand_cmd_ctl(struct nand_chip *this, int dat,
+ unsigned int ctrl)
+{
+ unsigned long nandaddr = (unsigned long)this->legacy.IO_ADDR_W;
+
+ dsb();
+
+ if (ctrl & NAND_CTRL_CHANGE) {
+ if (ctrl & NAND_ALE)
+ nandaddr |= (1 << 3);
+ else
+ nandaddr &= ~(1 << 3);
+ if (ctrl & NAND_CLE)
+ nandaddr |= (1 << 2);
+ else
+ nandaddr &= ~(1 << 2);
+ if (ctrl & NAND_NCE)
+ nand_cs_on();
+ else
+ nand_cs_off();
+ }
+
+ dsb();
+ this->legacy.IO_ADDR_W = (void __iomem *)nandaddr;
+ if (dat != NAND_CMD_NONE)
+ writeb(dat, this->legacy.IO_ADDR_W);
+
+ dsb();
+}
+
+/* read device ready pin */
+static int cmx270_nand_device_ready(struct nand_chip *this)
+{
+ dsb();
+
+ return gpio_get_value(GPIO89_NAND_RB);
+}
+
+static struct mtd_partition cmx270_partition_info[] = {
+ [0] = {
+ .name = "cmx270-0",
+ .offset = 0,
+ .size = MTDPART_SIZ_FULL
+ },
+};
+
+struct platform_nand_data cmx270_nand_platdata = {
+ .chip = {
+ .nr_chips = 1,
+ .chip_offset = 0,
+ .nr_partitions = ARRAY_SIZE(cmx270_partition_info),
+ .partitions = cmx270_partition_info,
+ .chip_delay = 20,
+ },
+ .ctrl = {
+ .dev_ready = cmx270_nand_device_ready,
+ .cmd_ctrl = cmx270_nand_cmd_ctl,
+ },
+};
+
+static struct resource cmx270_nand_resource[] = {
+ [0] = {
+ /*
+ * The NAND is connected to D[16:23], hence the 2 byte offset
+ * here.
+ */
+ .start = PXA_CS1_PHYS + 2,
+ .end = PXA_CS1_PHYS + 2 + 12,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device cmx270_nand = {
+ .name = "gen_nand",
+ .num_resources = ARRAY_SIZE(cmx270_nand_resource),
+ .resource = cmx270_nand_resource,
+ .id = -1,
+ .dev = {
+ .platform_data = &cmx270_nand_platdata,
+ }
+};
+
+static void __init cmx270_init_nand(void)
+{
+ int err;
+
+ err = gpio_request(GPIO11_NAND_CS, "NAND CS");
+ if (err) {
+ pr_warn("CMX270: failed to request NAND CS gpio\n");
+ return;
+ }
+
+ gpio_direction_output(GPIO11_NAND_CS, 1);
+
+ err = gpio_request(GPIO89_NAND_RB, "NAND R/B");
+ if (err) {
+ pr_warn("CMX270: failed to request NAND R/B gpio\n");
+ gpio_free(GPIO11_NAND_CS);
+ return;
+ }
+
+ gpio_direction_input(GPIO89_NAND_RB);
+
+ platform_device_register(&cmx270_nand);
+}
+#else
+static inline void cmx270_init_nand(void) {}
+#endif
+
#if defined(CONFIG_SPI_PXA2XX) || defined(CONFIG_SPI_PXA2XX_MODULE)
static struct pxa2xx_spi_controller cm_x270_spi_info = {
.num_chipselect = 1,
@@ -413,6 +543,7 @@ void __init cmx270_init(void)
cmx270_init_rtc();
cmx270_init_mmc();
+ cmx270_init_nand();
cmx270_init_ohci();
cmx270_init_2700G();
cmx270_init_spi();
No need to have a dedicated driver for this controller, all we need to do is adjust the memory range offset to account for the fact that the chip is connected to D[16:23] and not D[0:7]. Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com> --- arch/arm/mach-pxa/cm-x270.c | 131 ++++++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+)