18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * BCM47XX NAND flash driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2012 Rafał Miłecki <zajec5@gmail.com> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include "bcm47xxnflash.h" 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/module.h> 118c2ecf20Sopenharmony_ci#include <linux/kernel.h> 128c2ecf20Sopenharmony_ci#include <linux/slab.h> 138c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 148c2ecf20Sopenharmony_ci#include <linux/bcma/bcma.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("NAND flash driver for BCMA bus"); 178c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 188c2ecf20Sopenharmony_ciMODULE_AUTHOR("Rafał Miłecki"); 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_cistatic const char *probes[] = { "bcm47xxpart", NULL }; 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_cistatic int bcm47xxnflash_probe(struct platform_device *pdev) 238c2ecf20Sopenharmony_ci{ 248c2ecf20Sopenharmony_ci struct bcma_nflash *nflash = dev_get_platdata(&pdev->dev); 258c2ecf20Sopenharmony_ci struct bcm47xxnflash *b47n; 268c2ecf20Sopenharmony_ci struct mtd_info *mtd; 278c2ecf20Sopenharmony_ci int err = 0; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci b47n = devm_kzalloc(&pdev->dev, sizeof(*b47n), GFP_KERNEL); 308c2ecf20Sopenharmony_ci if (!b47n) 318c2ecf20Sopenharmony_ci return -ENOMEM; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci nand_set_controller_data(&b47n->nand_chip, b47n); 348c2ecf20Sopenharmony_ci mtd = nand_to_mtd(&b47n->nand_chip); 358c2ecf20Sopenharmony_ci mtd->dev.parent = &pdev->dev; 368c2ecf20Sopenharmony_ci b47n->cc = container_of(nflash, struct bcma_drv_cc, nflash); 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci if (b47n->cc->core->bus->chipinfo.id == BCMA_CHIP_ID_BCM4706) { 398c2ecf20Sopenharmony_ci err = bcm47xxnflash_ops_bcm4706_init(b47n); 408c2ecf20Sopenharmony_ci } else { 418c2ecf20Sopenharmony_ci pr_err("Device not supported\n"); 428c2ecf20Sopenharmony_ci err = -ENOTSUPP; 438c2ecf20Sopenharmony_ci } 448c2ecf20Sopenharmony_ci if (err) { 458c2ecf20Sopenharmony_ci pr_err("Initialization failed: %d\n", err); 468c2ecf20Sopenharmony_ci return err; 478c2ecf20Sopenharmony_ci } 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, b47n); 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci err = mtd_device_parse_register(mtd, probes, NULL, NULL, 0); 528c2ecf20Sopenharmony_ci if (err) { 538c2ecf20Sopenharmony_ci pr_err("Failed to register MTD device: %d\n", err); 548c2ecf20Sopenharmony_ci return err; 558c2ecf20Sopenharmony_ci } 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci return 0; 588c2ecf20Sopenharmony_ci} 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistatic int bcm47xxnflash_remove(struct platform_device *pdev) 618c2ecf20Sopenharmony_ci{ 628c2ecf20Sopenharmony_ci struct bcm47xxnflash *nflash = platform_get_drvdata(pdev); 638c2ecf20Sopenharmony_ci struct nand_chip *chip = &nflash->nand_chip; 648c2ecf20Sopenharmony_ci int ret; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci ret = mtd_device_unregister(nand_to_mtd(chip)); 678c2ecf20Sopenharmony_ci WARN_ON(ret); 688c2ecf20Sopenharmony_ci nand_cleanup(chip); 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci return 0; 718c2ecf20Sopenharmony_ci} 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cistatic struct platform_driver bcm47xxnflash_driver = { 748c2ecf20Sopenharmony_ci .probe = bcm47xxnflash_probe, 758c2ecf20Sopenharmony_ci .remove = bcm47xxnflash_remove, 768c2ecf20Sopenharmony_ci .driver = { 778c2ecf20Sopenharmony_ci .name = "bcma_nflash", 788c2ecf20Sopenharmony_ci }, 798c2ecf20Sopenharmony_ci}; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cimodule_platform_driver(bcm47xxnflash_driver); 82