1/* 2 * This program is free software; you can redistribute it and/or modify it 3 * under the terms of the GNU General Public License version 2 as published 4 * by the Free Software Foundation. 5 * 6 * based on xway_nand.c 7 * Copyright �� 2012 John Crispin <blogic@openwrt.org> 8 * and oxnas_nand.c "NAND glue for Oxnas platforms" 9 * written by Ma Haijun <mahaijuns@gmail.com> 10 */ 11 12#include <linux/mtd/nand.h> 13#include <linux/of_gpio.h> 14#include <linux/of_platform.h> 15#include <linux/clk.h> 16#include <linux/reset.h> 17 18/* nand commands */ 19#define NAND_CMD_ALE BIT(18) 20#define NAND_CMD_CLE BIT(19) 21#define NAND_CMD_CS 0 22#define NAND_CMD_RESET 0xff 23#define NAND_CMD (NAND_CMD_CS | NAND_CMD_CLE) 24#define NAND_ADDR (NAND_CMD_CS | NAND_CMD_ALE) 25#define NAND_DATA (NAND_CMD_CS) 26 27static void oxnas_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) 28{ 29 struct nand_chip *this = mtd->priv; 30 unsigned long nandaddr = (unsigned long) this->IO_ADDR_W; 31 32 if (ctrl & NAND_CTRL_CHANGE) { 33 nandaddr &= ~(NAND_CMD | NAND_ADDR); 34 if (ctrl & NAND_CLE) 35 nandaddr |= NAND_CMD; 36 else if (ctrl & NAND_ALE) 37 nandaddr |= NAND_ADDR; 38 this->IO_ADDR_W = (void __iomem *) nandaddr; 39 } 40 41 if (cmd != NAND_CMD_NONE) 42 writeb(cmd, (void __iomem *) nandaddr); 43} 44 45static int oxnas_nand_probe(struct platform_device *pdev) 46{ 47 /* enable clock and release static block reset */ 48 struct clk *clk = of_clk_get(pdev->dev.of_node, 0); 49 50 if (IS_ERR(clk)) 51 return PTR_ERR(clk); 52 53 clk_prepare_enable(clk); 54 device_reset(&pdev->dev); 55 56 return 0; 57} 58 59static struct platform_nand_data oxnas_nand_data = { 60 .chip = { 61 .nr_chips = 1, 62 .chip_delay = 30, 63 }, 64 .ctrl = { 65 .probe = oxnas_nand_probe, 66 .cmd_ctrl = oxnas_cmd_ctrl, 67 } 68}; 69 70/* 71 * Try to find the node inside the DT. If it is available attach out 72 * platform_nand_data 73 */ 74static int __init oxnas_register_nand(void) 75{ 76 struct device_node *node; 77 struct platform_device *pdev; 78 79 node = of_find_compatible_node(NULL, NULL, "plxtech,nand-nas782x"); 80 if (!node) 81 return -ENOENT; 82 pdev = of_find_device_by_node(node); 83 if (!pdev) 84 return -EINVAL; 85 pdev->dev.platform_data = &oxnas_nand_data; 86 of_node_put(node); 87 return 0; 88} 89 90subsys_initcall(oxnas_register_nand); 91