From: Tomasz Figa <tomasz.figa@xxxxxxxxx> This patch adds support for instantation using Device Tree. Signed-off-by: Tomasz Figa <tomasz.figa@xxxxxxxxx> Signed-off-by: Paweł Chmiel <pawel.mikolaj.chmiel@xxxxxxxxx> Signed-off-by: Jonathan Bakker <xc-racer2@xxxxxxx> --- Changes from previous patchset - Adjust to having a nand child node as per binding feedback --- drivers/mtd/nand/onenand/onenand_samsung.c | 67 +++++++++++++++++++++- 1 file changed, 65 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/nand/onenand/onenand_samsung.c b/drivers/mtd/nand/onenand/onenand_samsung.c index 62014f8d27b6..0108c8c75d5b 100644 --- a/drivers/mtd/nand/onenand/onenand_samsung.c +++ b/drivers/mtd/nand/onenand/onenand_samsung.c @@ -22,6 +22,7 @@ #include <linux/dma-mapping.h> #include <linux/interrupt.h> #include <linux/io.h> +#include <linux/of.h> #include "samsung.h" @@ -832,8 +833,36 @@ static void s3c_onenand_setup(struct mtd_info *mtd) this->write_bufferram = onenand_write_bufferram; } +#ifdef CONFIG_OF +static const struct of_device_id s3c_onenand_of_match[] = { + { .compatible = "samsung,s3c6400-onenand", + .data = (void *)TYPE_S3C6400 }, + { .compatible = "samsung,s3c6410-onenand", + .data = (void *)TYPE_S3C6410 }, + { .compatible = "samsung,s5pv210-onenand", + .data = (void *)TYPE_S5PC110 }, + {}, +}; +MODULE_DEVICE_TABLE(of, onenand_s3c_dt_match); +#endif + +static enum soc_type s3c_onenand_get_device_id(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + + if (IS_ENABLED(CONFIG_OF) && np) { + const struct of_device_id *match; + + match = of_match_node(s3c_onenand_of_match, np); + return (enum soc_type)match->data; + } + + return platform_get_device_id(pdev)->driver_data; +} + static int s3c_onenand_probe(struct platform_device *pdev) { + struct device_node *np = pdev->dev.of_node; struct onenand_platform_data *pdata; struct onenand_chip *this; struct mtd_info *mtd; @@ -856,9 +885,10 @@ static int s3c_onenand_probe(struct platform_device *pdev) this = (struct onenand_chip *) &mtd[1]; mtd->name = dev_name(&pdev->dev); mtd->priv = this; + mtd->dev.of_node = np; mtd->dev.parent = &pdev->dev; onenand->pdev = pdev; - onenand->type = platform_get_device_id(pdev)->driver_data; + onenand->type = s3c_onenand_get_device_id(pdev); s3c_onenand_setup(mtd); @@ -867,7 +897,35 @@ static int s3c_onenand_probe(struct platform_device *pdev) if (IS_ERR(onenand->ctrl_base)) return PTR_ERR(onenand->ctrl_base); - r = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (np) { + /* Determine which CS to use - this driver only supports one */ + u32 cs = 0; + struct device_node *child_np; + struct device_node *extra_chip_np; + + child_np = of_get_next_available_child(np, NULL); + if (child_np == NULL) { + dev_err(&pdev->dev, "failed to get chip node\n"); + return -EINVAL; + } + + /* Warn if more than one chip as this unsupported */ + extra_chip_np = of_get_next_available_child(np, child_np); + if (extra_chip_np != NULL) { + dev_warn(&pdev->dev, "multiple chip nodes, using only first\n"); + of_node_put(extra_chip_np); + } + + err = of_property_read_u32(child_np, "reg", &cs); + of_node_put(child_np); + if (err < 0) + return err; + + r = platform_get_resource(pdev, IORESOURCE_MEM, cs + 1); + } else { + r = platform_get_resource(pdev, IORESOURCE_MEM, 1); + } + onenand->chip_base = devm_ioremap_resource(&pdev->dev, r); if (IS_ERR(onenand->chip_base)) return PTR_ERR(onenand->chip_base); @@ -917,6 +975,10 @@ static int s3c_onenand_probe(struct platform_device *pdev) } onenand->clk_bus = devm_clk_get(&pdev->dev, "bus"); + if (np && IS_ERR(onenand->clk_bus)) { + dev_err(&pdev->dev, "failed to get bus clock\n"); + return PTR_ERR(onenand->clk_bus); + } if (!IS_ERR(onenand->clk_bus)) clk_prepare_enable(onenand->clk_bus); @@ -998,6 +1060,7 @@ static struct platform_driver s3c_onenand_driver = { .driver = { .name = "samsung-onenand", .pm = &s3c_pm_ops, + .of_match_table = of_match_ptr(s3c_onenand_of_match), }, .id_table = s3c_onenand_driver_ids, .probe = s3c_onenand_probe, -- 2.30.2