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