1846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky/* 2846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky * Copyright (C) 2006-2007 PA Semi, Inc 3846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky * 4846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky * Author: Egor Martovetsky <egor@pasemi.com> 5846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky * Maintained by: Olof Johansson <olof@lixom.net> 6846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky * 7846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky * Driver for the PWRficient onchip NAND flash interface 8846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky * 9846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky * This program is free software; you can redistribute it and/or modify 10846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky * it under the terms of the GNU General Public License version 2 as 11846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky * published by the Free Software Foundation. 12846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky * 13846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky * This program is distributed in the hope that it will be useful, 14846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky * but WITHOUT ANY WARRANTY; without even the implied warranty of 15846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky * GNU General Public License for more details. 17846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky * 18846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky * You should have received a copy of the GNU General Public License 19846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky * along with this program; if not, write to the Free Software 20846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky */ 22846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky 23846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky#undef DEBUG 24846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky 25846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky#include <linux/slab.h> 26846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky#include <linux/module.h> 27846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky#include <linux/mtd/mtd.h> 28846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky#include <linux/mtd/nand.h> 29846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky#include <linux/mtd/nand_ecc.h> 305af5073004071cedd0343eee51d77955037ec6f3Rob Herring#include <linux/of_address.h> 315af5073004071cedd0343eee51d77955037ec6f3Rob Herring#include <linux/of_irq.h> 32846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky#include <linux/of_platform.h> 33846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky#include <linux/platform_device.h> 34846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky#include <linux/pci.h> 35846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky 36846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky#include <asm/io.h> 37846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky 38846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky#define LBICTRL_LPCCTL_NR 0x00004000 39846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky#define CLE_PIN_CTL 15 40846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky#define ALE_PIN_CTL 14 41846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky 42846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetskystatic unsigned int lpcctl; 43846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetskystatic struct mtd_info *pasemi_nand_mtd; 44846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetskystatic const char driver_name[] = "pasemi-nand"; 45846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky 46846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetskystatic void pasemi_read_buf(struct mtd_info *mtd, u_char *buf, int len) 47846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky{ 48846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky struct nand_chip *chip = mtd->priv; 49846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky 50846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky while (len > 0x800) { 51846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky memcpy_fromio(buf, chip->IO_ADDR_R, 0x800); 52846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky buf += 0x800; 53846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky len -= 0x800; 54846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky } 55846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky memcpy_fromio(buf, chip->IO_ADDR_R, len); 56846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky} 57846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky 58846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetskystatic void pasemi_write_buf(struct mtd_info *mtd, const u_char *buf, int len) 59846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky{ 60846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky struct nand_chip *chip = mtd->priv; 61846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky 62846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky while (len > 0x800) { 63846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky memcpy_toio(chip->IO_ADDR_R, buf, 0x800); 64846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky buf += 0x800; 65846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky len -= 0x800; 66846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky } 67846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky memcpy_toio(chip->IO_ADDR_R, buf, len); 68846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky} 69846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky 70846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetskystatic void pasemi_hwcontrol(struct mtd_info *mtd, int cmd, 71846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky unsigned int ctrl) 72846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky{ 73846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky struct nand_chip *chip = mtd->priv; 74846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky 75846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky if (cmd == NAND_CMD_NONE) 76846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky return; 77846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky 78846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky if (ctrl & NAND_CLE) 79846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky out_8(chip->IO_ADDR_W + (1 << CLE_PIN_CTL), cmd); 80846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky else 81846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky out_8(chip->IO_ADDR_W + (1 << ALE_PIN_CTL), cmd); 82846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky 83846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky /* Push out posted writes */ 84846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky eieio(); 85846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky inl(lpcctl); 86846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky} 87846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky 88846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetskyint pasemi_device_ready(struct mtd_info *mtd) 89846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky{ 90846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky return !!(inl(lpcctl) & LBICTRL_LPCCTL_NR); 91846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky} 92846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky 9306f25510692385ed4dadd23f7d3d064d1ab11c2dBill Pembertonstatic int pasemi_nand_probe(struct platform_device *ofdev) 94846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky{ 95846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky struct pci_dev *pdev; 9661c7a080a5a061c976988fd4b844dfb468dda255Grant Likely struct device_node *np = ofdev->dev.of_node; 97846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky struct resource res; 98846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky struct nand_chip *chip; 99846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky int err = 0; 100846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky 101846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky err = of_address_to_resource(np, 0, &res); 102846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky 103846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky if (err) 104846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky return -EINVAL; 105846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky 106846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky /* We only support one device at the moment */ 107846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky if (pasemi_nand_mtd) 108846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky return -ENODEV; 109846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky 11023079f94daabc4e06436ab2b643fac31dec017d1Joe Perches pr_debug("pasemi_nand at %pR\n", &res); 111846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky 112846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky /* Allocate memory for MTD device structure and private data */ 113846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky pasemi_nand_mtd = kzalloc(sizeof(struct mtd_info) + 114846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky sizeof(struct nand_chip), GFP_KERNEL); 115846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky if (!pasemi_nand_mtd) { 116846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky printk(KERN_WARNING 117846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky "Unable to allocate PASEMI NAND MTD device structure\n"); 118846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky err = -ENOMEM; 119846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky goto out; 120846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky } 121846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky 122846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky /* Get pointer to private data */ 123846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky chip = (struct nand_chip *)&pasemi_nand_mtd[1]; 124846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky 125846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky /* Link the private data with the MTD structure */ 126846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky pasemi_nand_mtd->priv = chip; 127846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky pasemi_nand_mtd->owner = THIS_MODULE; 128846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky 129846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky chip->IO_ADDR_R = of_iomap(np, 0); 130846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky chip->IO_ADDR_W = chip->IO_ADDR_R; 131846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky 132846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky if (!chip->IO_ADDR_R) { 133846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky err = -EIO; 134846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky goto out_mtd; 135846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky } 136846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky 137846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa008, NULL); 138846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky if (!pdev) { 139846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky err = -ENODEV; 140846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky goto out_ior; 141846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky } 142846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky 143846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky lpcctl = pci_resource_start(pdev, 0); 144d94762989103b5e29938d8a7b0112e72c4633265Julia Lawall pci_dev_put(pdev); 145846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky 146846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky if (!request_region(lpcctl, 4, driver_name)) { 147846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky err = -EBUSY; 148846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky goto out_ior; 149846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky } 150846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky 151846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky chip->cmd_ctrl = pasemi_hwcontrol; 152846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky chip->dev_ready = pasemi_device_ready; 153846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky chip->read_buf = pasemi_read_buf; 154846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky chip->write_buf = pasemi_write_buf; 155846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky chip->chip_delay = 0; 156846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky chip->ecc.mode = NAND_ECC_SOFT; 157846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky 158846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky /* Enable the following for a flash based bad block table */ 159bb9ebd4e714385a2592a482845865ef2d58b2868Brian Norris chip->bbt_options = NAND_BBT_USE_FLASH; 160846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky 16125985edcedea6396277003854657b5f3cb31a628Lucas De Marchi /* Scan to find existence of the device */ 162846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky if (nand_scan(pasemi_nand_mtd, 1)) { 163846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky err = -ENXIO; 164846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky goto out_lpc; 165846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky } 166846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky 167ee0e87b174bb41f0310cf089262bf5dd8f95a212Jamie Iles if (mtd_device_register(pasemi_nand_mtd, NULL, 0)) { 168846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky printk(KERN_ERR "pasemi_nand: Unable to register MTD device\n"); 169846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky err = -ENODEV; 170846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky goto out_lpc; 171846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky } 172846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky 1734712fff9be0f4a41f7add146cee88a9b945215d7Stephen Rothwell printk(KERN_INFO "PA Semi NAND flash at %08llx, control at I/O %x\n", 174846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky res.start, lpcctl); 175846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky 176846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky return 0; 177846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky 178846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky out_lpc: 179846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky release_region(lpcctl, 4); 180846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky out_ior: 181846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky iounmap(chip->IO_ADDR_R); 182846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky out_mtd: 183846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky kfree(pasemi_nand_mtd); 184846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky out: 185846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky return err; 186846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky} 187846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky 188810b7e060c14110d8f580daaf77fab3a7d950483Bill Pembertonstatic int pasemi_nand_remove(struct platform_device *ofdev) 189846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky{ 190846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky struct nand_chip *chip; 191846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky 192846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky if (!pasemi_nand_mtd) 193846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky return 0; 194846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky 195846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky chip = pasemi_nand_mtd->priv; 196846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky 197846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky /* Release resources, unregister device */ 198846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky nand_release(pasemi_nand_mtd); 199846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky 200846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky release_region(lpcctl, 4); 201846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky 202846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky iounmap(chip->IO_ADDR_R); 203846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky 204846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky /* Free the MTD device structure */ 205846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky kfree(pasemi_nand_mtd); 206846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky 207846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky pasemi_nand_mtd = NULL; 208846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky 209846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky return 0; 210846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky} 211846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky 212b2d4fbab79bd2b121c56db757c3a0f06ec7e0868Márton Némethstatic const struct of_device_id pasemi_nand_match[] = 213846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky{ 214846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky { 215846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky .compatible = "pasemi,localbus-nand", 216846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky }, 217846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky {}, 218846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky}; 219846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky 220846fc31d06e54ad94026da11da0668c050fe777eEgor MartovetskyMODULE_DEVICE_TABLE(of, pasemi_nand_match); 221846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky 2221c48a5c93da63132b92c4bbcd18e690c51539df6Grant Likelystatic struct platform_driver pasemi_nand_driver = 223846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky{ 2244018294b53d1dae026880e45f174c1cc63b5d435Grant Likely .driver = { 2258ca14e12a75216060e5dfbfe28a5efc5c230e08cGeert Uytterhoeven .name = driver_name, 2264018294b53d1dae026880e45f174c1cc63b5d435Grant Likely .owner = THIS_MODULE, 2274018294b53d1dae026880e45f174c1cc63b5d435Grant Likely .of_match_table = pasemi_nand_match, 2284018294b53d1dae026880e45f174c1cc63b5d435Grant Likely }, 229846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky .probe = pasemi_nand_probe, 230846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky .remove = pasemi_nand_remove, 231846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky}; 232846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky 233f99640dee209df4730f35a28b02693affd571ad5Axel Linmodule_platform_driver(pasemi_nand_driver); 234846fc31d06e54ad94026da11da0668c050fe777eEgor Martovetsky 235846fc31d06e54ad94026da11da0668c050fe777eEgor MartovetskyMODULE_LICENSE("GPL"); 236846fc31d06e54ad94026da11da0668c050fe777eEgor MartovetskyMODULE_AUTHOR("Egor Martovetsky <egor@pasemi.com>"); 237846fc31d06e54ad94026da11da0668c050fe777eEgor MartovetskyMODULE_DESCRIPTION("NAND flash interface driver for PA Semi PWRficient"); 238