162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * BCM47XX NAND flash driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2012 Rafał Miłecki <zajec5@gmail.com>
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include "bcm47xxnflash.h"
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/module.h>
1162306a36Sopenharmony_ci#include <linux/kernel.h>
1262306a36Sopenharmony_ci#include <linux/slab.h>
1362306a36Sopenharmony_ci#include <linux/platform_device.h>
1462306a36Sopenharmony_ci#include <linux/bcma/bcma.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ciMODULE_DESCRIPTION("NAND flash driver for BCMA bus");
1762306a36Sopenharmony_ciMODULE_LICENSE("GPL");
1862306a36Sopenharmony_ciMODULE_AUTHOR("Rafał Miłecki");
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_cistatic const char *probes[] = { "bcm47xxpart", NULL };
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_cistatic int bcm47xxnflash_probe(struct platform_device *pdev)
2362306a36Sopenharmony_ci{
2462306a36Sopenharmony_ci	struct bcma_nflash *nflash = dev_get_platdata(&pdev->dev);
2562306a36Sopenharmony_ci	struct bcm47xxnflash *b47n;
2662306a36Sopenharmony_ci	struct mtd_info *mtd;
2762306a36Sopenharmony_ci	int err = 0;
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci	b47n = devm_kzalloc(&pdev->dev, sizeof(*b47n), GFP_KERNEL);
3062306a36Sopenharmony_ci	if (!b47n)
3162306a36Sopenharmony_ci		return -ENOMEM;
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci	nand_set_controller_data(&b47n->nand_chip, b47n);
3462306a36Sopenharmony_ci	mtd = nand_to_mtd(&b47n->nand_chip);
3562306a36Sopenharmony_ci	mtd->dev.parent = &pdev->dev;
3662306a36Sopenharmony_ci	b47n->cc = container_of(nflash, struct bcma_drv_cc, nflash);
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	if (b47n->cc->core->bus->chipinfo.id == BCMA_CHIP_ID_BCM4706) {
3962306a36Sopenharmony_ci		err = bcm47xxnflash_ops_bcm4706_init(b47n);
4062306a36Sopenharmony_ci	} else {
4162306a36Sopenharmony_ci		pr_err("Device not supported\n");
4262306a36Sopenharmony_ci		err = -ENOTSUPP;
4362306a36Sopenharmony_ci	}
4462306a36Sopenharmony_ci	if (err) {
4562306a36Sopenharmony_ci		pr_err("Initialization failed: %d\n", err);
4662306a36Sopenharmony_ci		return err;
4762306a36Sopenharmony_ci	}
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	platform_set_drvdata(pdev, b47n);
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	err = mtd_device_parse_register(mtd, probes, NULL, NULL, 0);
5262306a36Sopenharmony_ci	if (err) {
5362306a36Sopenharmony_ci		pr_err("Failed to register MTD device: %d\n", err);
5462306a36Sopenharmony_ci		return err;
5562306a36Sopenharmony_ci	}
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	return 0;
5862306a36Sopenharmony_ci}
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_cistatic void bcm47xxnflash_remove(struct platform_device *pdev)
6162306a36Sopenharmony_ci{
6262306a36Sopenharmony_ci	struct bcm47xxnflash *nflash = platform_get_drvdata(pdev);
6362306a36Sopenharmony_ci	struct nand_chip *chip = &nflash->nand_chip;
6462306a36Sopenharmony_ci	int ret;
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	ret = mtd_device_unregister(nand_to_mtd(chip));
6762306a36Sopenharmony_ci	WARN_ON(ret);
6862306a36Sopenharmony_ci	nand_cleanup(chip);
6962306a36Sopenharmony_ci}
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_cistatic struct platform_driver bcm47xxnflash_driver = {
7262306a36Sopenharmony_ci	.probe	= bcm47xxnflash_probe,
7362306a36Sopenharmony_ci	.remove_new = bcm47xxnflash_remove,
7462306a36Sopenharmony_ci	.driver = {
7562306a36Sopenharmony_ci		.name = "bcma_nflash",
7662306a36Sopenharmony_ci	},
7762306a36Sopenharmony_ci};
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_cimodule_platform_driver(bcm47xxnflash_driver);
80