|
@@ -29,6 +29,9 @@
|
|
|
#include <linux/dma-mapping.h>
|
|
|
#include <linux/interrupt.h>
|
|
|
#include <linux/io.h>
|
|
|
+#include <linux/of.h>
|
|
|
+#include <linux/of_device.h>
|
|
|
+#include <linux/of_mtd.h>
|
|
|
#include <linux/platform_device.h>
|
|
|
#include <linux/pm_runtime.h>
|
|
|
#include <linux/sh_dma.h>
|
|
@@ -1016,6 +1019,73 @@ static irqreturn_t flctl_handle_flste(int irq, void *dev_id)
|
|
|
return IRQ_HANDLED;
|
|
|
}
|
|
|
|
|
|
+#ifdef CONFIG_OF
|
|
|
+struct flctl_soc_config {
|
|
|
+ unsigned long flcmncr_val;
|
|
|
+ unsigned has_hwecc:1;
|
|
|
+ unsigned use_holden:1;
|
|
|
+};
|
|
|
+
|
|
|
+static struct flctl_soc_config flctl_sh7372_config = {
|
|
|
+ .flcmncr_val = CLK_16B_12L_4H | TYPESEL_SET | SHBUSSEL,
|
|
|
+ .has_hwecc = 1,
|
|
|
+ .use_holden = 1,
|
|
|
+};
|
|
|
+
|
|
|
+static const struct of_device_id of_flctl_match[] = {
|
|
|
+ { .compatible = "renesas,shmobile-flctl-sh7372",
|
|
|
+ .data = &flctl_sh7372_config },
|
|
|
+ {},
|
|
|
+};
|
|
|
+MODULE_DEVICE_TABLE(of, of_flctl_match);
|
|
|
+
|
|
|
+static struct sh_flctl_platform_data *flctl_parse_dt(struct device *dev)
|
|
|
+{
|
|
|
+ const struct of_device_id *match;
|
|
|
+ struct flctl_soc_config *config;
|
|
|
+ struct sh_flctl_platform_data *pdata;
|
|
|
+ struct device_node *dn = dev->of_node;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ match = of_match_device(of_flctl_match, dev);
|
|
|
+ if (match)
|
|
|
+ config = (struct flctl_soc_config *)match->data;
|
|
|
+ else {
|
|
|
+ dev_err(dev, "%s: no OF configuration attached\n", __func__);
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ pdata = devm_kzalloc(dev, sizeof(struct sh_flctl_platform_data),
|
|
|
+ GFP_KERNEL);
|
|
|
+ if (!pdata) {
|
|
|
+ dev_err(dev, "%s: failed to allocate config data\n", __func__);
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* set SoC specific options */
|
|
|
+ pdata->flcmncr_val = config->flcmncr_val;
|
|
|
+ pdata->has_hwecc = config->has_hwecc;
|
|
|
+ pdata->use_holden = config->use_holden;
|
|
|
+
|
|
|
+ /* parse user defined options */
|
|
|
+ ret = of_get_nand_bus_width(dn);
|
|
|
+ if (ret == 16)
|
|
|
+ pdata->flcmncr_val |= SEL_16BIT;
|
|
|
+ else if (ret != 8) {
|
|
|
+ dev_err(dev, "%s: invalid bus width\n", __func__);
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ return pdata;
|
|
|
+}
|
|
|
+#else /* CONFIG_OF */
|
|
|
+#define of_flctl_match NULL
|
|
|
+static struct sh_flctl_platform_data *flctl_parse_dt(struct device *dev)
|
|
|
+{
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+#endif /* CONFIG_OF */
|
|
|
+
|
|
|
static int __devinit flctl_probe(struct platform_device *pdev)
|
|
|
{
|
|
|
struct resource *res;
|
|
@@ -1025,12 +1095,7 @@ static int __devinit flctl_probe(struct platform_device *pdev)
|
|
|
struct sh_flctl_platform_data *pdata;
|
|
|
int ret = -ENXIO;
|
|
|
int irq;
|
|
|
-
|
|
|
- pdata = pdev->dev.platform_data;
|
|
|
- if (pdata == NULL) {
|
|
|
- dev_err(&pdev->dev, "no platform data defined\n");
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
+ struct mtd_part_parser_data ppdata = {};
|
|
|
|
|
|
flctl = kzalloc(sizeof(struct sh_flctl), GFP_KERNEL);
|
|
|
if (!flctl) {
|
|
@@ -1062,6 +1127,17 @@ static int __devinit flctl_probe(struct platform_device *pdev)
|
|
|
goto err_flste;
|
|
|
}
|
|
|
|
|
|
+ if (pdev->dev.of_node)
|
|
|
+ pdata = flctl_parse_dt(&pdev->dev);
|
|
|
+ else
|
|
|
+ pdata = pdev->dev.platform_data;
|
|
|
+
|
|
|
+ if (!pdata) {
|
|
|
+ dev_err(&pdev->dev, "no setup data defined\n");
|
|
|
+ ret = -EINVAL;
|
|
|
+ goto err_pdata;
|
|
|
+ }
|
|
|
+
|
|
|
platform_set_drvdata(pdev, flctl);
|
|
|
flctl_mtd = &flctl->mtd;
|
|
|
nand = &flctl->chip;
|
|
@@ -1104,13 +1180,16 @@ static int __devinit flctl_probe(struct platform_device *pdev)
|
|
|
if (ret)
|
|
|
goto err_chip;
|
|
|
|
|
|
- mtd_device_register(flctl_mtd, pdata->parts, pdata->nr_parts);
|
|
|
+ ppdata.of_node = pdev->dev.of_node;
|
|
|
+ ret = mtd_device_parse_register(flctl_mtd, NULL, &ppdata, pdata->parts,
|
|
|
+ pdata->nr_parts);
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
err_chip:
|
|
|
flctl_release_dma(flctl);
|
|
|
pm_runtime_disable(&pdev->dev);
|
|
|
+err_pdata:
|
|
|
free_irq(irq, flctl);
|
|
|
err_flste:
|
|
|
iounmap(flctl->reg);
|
|
@@ -1138,6 +1217,7 @@ static struct platform_driver flctl_driver = {
|
|
|
.driver = {
|
|
|
.name = "sh_flctl",
|
|
|
.owner = THIS_MODULE,
|
|
|
+ .of_match_table = of_flctl_match,
|
|
|
},
|
|
|
};
|
|
|
|