Dinh Nguyen | 30f9f2f | 2012-09-27 10:58:06 -0600 | [diff] [blame] | 1 | /* |
| 2 | * NAND Flash Controller Device Driver for DT |
| 3 | * |
| 4 | * Copyright © 2011, Picochip. |
| 5 | * |
| 6 | * This program is free software; you can redistribute it and/or modify it |
| 7 | * under the terms and conditions of the GNU General Public License, |
| 8 | * version 2, as published by the Free Software Foundation. |
| 9 | * |
| 10 | * This program is distributed in the hope it will be useful, but WITHOUT |
| 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| 12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
| 13 | * more details. |
| 14 | */ |
| 15 | #include <linux/clk.h> |
| 16 | #include <linux/err.h> |
| 17 | #include <linux/io.h> |
| 18 | #include <linux/ioport.h> |
| 19 | #include <linux/kernel.h> |
| 20 | #include <linux/module.h> |
| 21 | #include <linux/platform_device.h> |
| 22 | #include <linux/of.h> |
| 23 | #include <linux/of_device.h> |
Dinh Nguyen | 30f9f2f | 2012-09-27 10:58:06 -0600 | [diff] [blame] | 24 | |
| 25 | #include "denali.h" |
| 26 | |
| 27 | struct denali_dt { |
| 28 | struct denali_nand_info denali; |
| 29 | struct clk *clk; |
| 30 | }; |
| 31 | |
Masahiro Yamada | be72a4a | 2017-03-23 05:07:07 +0900 | [diff] [blame] | 32 | struct denali_dt_data { |
Masahiro Yamada | e7beeee | 2017-03-30 15:45:57 +0900 | [diff] [blame] | 33 | unsigned int revision; |
Masahiro Yamada | be72a4a | 2017-03-23 05:07:07 +0900 | [diff] [blame] | 34 | unsigned int caps; |
Masahiro Yamada | 7de117f | 2017-06-07 20:52:12 +0900 | [diff] [blame] | 35 | const struct nand_ecc_caps *ecc_caps; |
Masahiro Yamada | be72a4a | 2017-03-23 05:07:07 +0900 | [diff] [blame] | 36 | }; |
| 37 | |
Masahiro Yamada | 7de117f | 2017-06-07 20:52:12 +0900 | [diff] [blame] | 38 | NAND_ECC_CAPS_SINGLE(denali_socfpga_ecc_caps, denali_calc_ecc_bytes, |
| 39 | 512, 8, 15); |
Masahiro Yamada | a56609c | 2017-03-30 15:45:53 +0900 | [diff] [blame] | 40 | static const struct denali_dt_data denali_socfpga_data = { |
| 41 | .caps = DENALI_CAP_HW_ECC_FIXUP, |
Masahiro Yamada | 7de117f | 2017-06-07 20:52:12 +0900 | [diff] [blame] | 42 | .ecc_caps = &denali_socfpga_ecc_caps, |
Masahiro Yamada | a56609c | 2017-03-30 15:45:53 +0900 | [diff] [blame] | 43 | }; |
Dinh Nguyen | 30f9f2f | 2012-09-27 10:58:06 -0600 | [diff] [blame] | 44 | |
Masahiro Yamada | 91300dd | 2017-06-07 20:52:14 +0900 | [diff] [blame] | 45 | NAND_ECC_CAPS_SINGLE(denali_uniphier_v5a_ecc_caps, denali_calc_ecc_bytes, |
| 46 | 1024, 8, 16, 24); |
| 47 | static const struct denali_dt_data denali_uniphier_v5a_data = { |
| 48 | .caps = DENALI_CAP_HW_ECC_FIXUP | |
| 49 | DENALI_CAP_DMA_64BIT, |
| 50 | .ecc_caps = &denali_uniphier_v5a_ecc_caps, |
| 51 | }; |
| 52 | |
| 53 | NAND_ECC_CAPS_SINGLE(denali_uniphier_v5b_ecc_caps, denali_calc_ecc_bytes, |
| 54 | 1024, 8, 16); |
| 55 | static const struct denali_dt_data denali_uniphier_v5b_data = { |
| 56 | .revision = 0x0501, |
| 57 | .caps = DENALI_CAP_HW_ECC_FIXUP | |
| 58 | DENALI_CAP_DMA_64BIT, |
| 59 | .ecc_caps = &denali_uniphier_v5b_ecc_caps, |
| 60 | }; |
| 61 | |
Masahiro Yamada | a56609c | 2017-03-30 15:45:53 +0900 | [diff] [blame] | 62 | static const struct of_device_id denali_nand_dt_ids[] = { |
| 63 | { |
| 64 | .compatible = "altr,socfpga-denali-nand", |
| 65 | .data = &denali_socfpga_data, |
| 66 | }, |
Masahiro Yamada | 91300dd | 2017-06-07 20:52:14 +0900 | [diff] [blame] | 67 | { |
| 68 | .compatible = "socionext,uniphier-denali-nand-v5a", |
| 69 | .data = &denali_uniphier_v5a_data, |
| 70 | }, |
| 71 | { |
| 72 | .compatible = "socionext,uniphier-denali-nand-v5b", |
| 73 | .data = &denali_uniphier_v5b_data, |
| 74 | }, |
Masahiro Yamada | a56609c | 2017-03-30 15:45:53 +0900 | [diff] [blame] | 75 | { /* sentinel */ } |
| 76 | }; |
Dinh Nguyen | 30f9f2f | 2012-09-27 10:58:06 -0600 | [diff] [blame] | 77 | MODULE_DEVICE_TABLE(of, denali_nand_dt_ids); |
| 78 | |
Masahiro Yamada | 3f5c358 | 2017-03-30 15:45:56 +0900 | [diff] [blame] | 79 | static int denali_dt_probe(struct platform_device *pdev) |
Dinh Nguyen | 30f9f2f | 2012-09-27 10:58:06 -0600 | [diff] [blame] | 80 | { |
Masahiro Yamada | 2b8c92b | 2017-06-06 08:21:40 +0900 | [diff] [blame] | 81 | struct resource *res; |
Dinh Nguyen | 30f9f2f | 2012-09-27 10:58:06 -0600 | [diff] [blame] | 82 | struct denali_dt *dt; |
Masahiro Yamada | be72a4a | 2017-03-23 05:07:07 +0900 | [diff] [blame] | 83 | const struct denali_dt_data *data; |
Dinh Nguyen | 30f9f2f | 2012-09-27 10:58:06 -0600 | [diff] [blame] | 84 | struct denali_nand_info *denali; |
| 85 | int ret; |
Dinh Nguyen | 30f9f2f | 2012-09-27 10:58:06 -0600 | [diff] [blame] | 86 | |
Masahiro Yamada | 3f5c358 | 2017-03-30 15:45:56 +0900 | [diff] [blame] | 87 | dt = devm_kzalloc(&pdev->dev, sizeof(*dt), GFP_KERNEL); |
Dinh Nguyen | 30f9f2f | 2012-09-27 10:58:06 -0600 | [diff] [blame] | 88 | if (!dt) |
| 89 | return -ENOMEM; |
| 90 | denali = &dt->denali; |
| 91 | |
Masahiro Yamada | 3f5c358 | 2017-03-30 15:45:56 +0900 | [diff] [blame] | 92 | data = of_device_get_match_data(&pdev->dev); |
Masahiro Yamada | e7beeee | 2017-03-30 15:45:57 +0900 | [diff] [blame] | 93 | if (data) { |
| 94 | denali->revision = data->revision; |
Masahiro Yamada | be72a4a | 2017-03-23 05:07:07 +0900 | [diff] [blame] | 95 | denali->caps = data->caps; |
Masahiro Yamada | 7de117f | 2017-06-07 20:52:12 +0900 | [diff] [blame] | 96 | denali->ecc_caps = data->ecc_caps; |
Masahiro Yamada | e7beeee | 2017-03-30 15:45:57 +0900 | [diff] [blame] | 97 | } |
Masahiro Yamada | be72a4a | 2017-03-23 05:07:07 +0900 | [diff] [blame] | 98 | |
Masahiro Yamada | 3f5c358 | 2017-03-30 15:45:56 +0900 | [diff] [blame] | 99 | denali->dev = &pdev->dev; |
| 100 | denali->irq = platform_get_irq(pdev, 0); |
Dinh Nguyen | 30f9f2f | 2012-09-27 10:58:06 -0600 | [diff] [blame] | 101 | if (denali->irq < 0) { |
Masahiro Yamada | 3f5c358 | 2017-03-30 15:45:56 +0900 | [diff] [blame] | 102 | dev_err(&pdev->dev, "no irq defined\n"); |
Sachin Kamat | 2f2ff14 | 2013-03-18 15:11:13 +0530 | [diff] [blame] | 103 | return denali->irq; |
Dinh Nguyen | 30f9f2f | 2012-09-27 10:58:06 -0600 | [diff] [blame] | 104 | } |
| 105 | |
Masahiro Yamada | 2b8c92b | 2017-06-06 08:21:40 +0900 | [diff] [blame] | 106 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "denali_reg"); |
Masahiro Yamada | 0d3a966 | 2017-06-16 14:36:39 +0900 | [diff] [blame] | 107 | denali->reg = devm_ioremap_resource(&pdev->dev, res); |
| 108 | if (IS_ERR(denali->reg)) |
| 109 | return PTR_ERR(denali->reg); |
Dinh Nguyen | 30f9f2f | 2012-09-27 10:58:06 -0600 | [diff] [blame] | 110 | |
Masahiro Yamada | 2b8c92b | 2017-06-06 08:21:40 +0900 | [diff] [blame] | 111 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_data"); |
Masahiro Yamada | 0d3a966 | 2017-06-16 14:36:39 +0900 | [diff] [blame] | 112 | denali->host = devm_ioremap_resource(&pdev->dev, res); |
| 113 | if (IS_ERR(denali->host)) |
| 114 | return PTR_ERR(denali->host); |
Dinh Nguyen | 30f9f2f | 2012-09-27 10:58:06 -0600 | [diff] [blame] | 115 | |
Masahiro Yamada | 3f5c358 | 2017-03-30 15:45:56 +0900 | [diff] [blame] | 116 | dt->clk = devm_clk_get(&pdev->dev, NULL); |
Dinh Nguyen | 30f9f2f | 2012-09-27 10:58:06 -0600 | [diff] [blame] | 117 | if (IS_ERR(dt->clk)) { |
Masahiro Yamada | 3f5c358 | 2017-03-30 15:45:56 +0900 | [diff] [blame] | 118 | dev_err(&pdev->dev, "no clk available\n"); |
Dinh Nguyen | 30f9f2f | 2012-09-27 10:58:06 -0600 | [diff] [blame] | 119 | return PTR_ERR(dt->clk); |
| 120 | } |
| 121 | clk_prepare_enable(dt->clk); |
| 122 | |
Masahiro Yamada | 1bb8866 | 2017-06-13 22:45:37 +0900 | [diff] [blame] | 123 | denali->clk_x_rate = clk_get_rate(dt->clk); |
| 124 | |
Dinh Nguyen | 30f9f2f | 2012-09-27 10:58:06 -0600 | [diff] [blame] | 125 | ret = denali_init(denali); |
| 126 | if (ret) |
| 127 | goto out_disable_clk; |
| 128 | |
Masahiro Yamada | 3f5c358 | 2017-03-30 15:45:56 +0900 | [diff] [blame] | 129 | platform_set_drvdata(pdev, dt); |
Dinh Nguyen | 30f9f2f | 2012-09-27 10:58:06 -0600 | [diff] [blame] | 130 | return 0; |
| 131 | |
| 132 | out_disable_clk: |
| 133 | clk_disable_unprepare(dt->clk); |
Dinh Nguyen | 30f9f2f | 2012-09-27 10:58:06 -0600 | [diff] [blame] | 134 | |
| 135 | return ret; |
| 136 | } |
| 137 | |
Masahiro Yamada | 3f5c358 | 2017-03-30 15:45:56 +0900 | [diff] [blame] | 138 | static int denali_dt_remove(struct platform_device *pdev) |
Dinh Nguyen | 30f9f2f | 2012-09-27 10:58:06 -0600 | [diff] [blame] | 139 | { |
Masahiro Yamada | 3f5c358 | 2017-03-30 15:45:56 +0900 | [diff] [blame] | 140 | struct denali_dt *dt = platform_get_drvdata(pdev); |
Dinh Nguyen | 30f9f2f | 2012-09-27 10:58:06 -0600 | [diff] [blame] | 141 | |
| 142 | denali_remove(&dt->denali); |
Masahiro Yamada | a1a2617 | 2016-11-03 02:21:04 +0900 | [diff] [blame] | 143 | clk_disable_unprepare(dt->clk); |
Dinh Nguyen | 30f9f2f | 2012-09-27 10:58:06 -0600 | [diff] [blame] | 144 | |
| 145 | return 0; |
| 146 | } |
| 147 | |
| 148 | static struct platform_driver denali_dt_driver = { |
| 149 | .probe = denali_dt_probe, |
Bill Pemberton | 5153b88 | 2012-11-19 13:21:24 -0500 | [diff] [blame] | 150 | .remove = denali_dt_remove, |
Dinh Nguyen | 30f9f2f | 2012-09-27 10:58:06 -0600 | [diff] [blame] | 151 | .driver = { |
| 152 | .name = "denali-nand-dt", |
Sachin Kamat | ef54f87 | 2013-03-18 15:11:14 +0530 | [diff] [blame] | 153 | .of_match_table = denali_nand_dt_ids, |
Dinh Nguyen | 30f9f2f | 2012-09-27 10:58:06 -0600 | [diff] [blame] | 154 | }, |
| 155 | }; |
| 156 | |
Sachin Kamat | 82fc812 | 2013-03-18 15:11:12 +0530 | [diff] [blame] | 157 | module_platform_driver(denali_dt_driver); |
Dinh Nguyen | 30f9f2f | 2012-09-27 10:58:06 -0600 | [diff] [blame] | 158 | |
| 159 | MODULE_LICENSE("GPL"); |
| 160 | MODULE_AUTHOR("Jamie Iles"); |
| 161 | MODULE_DESCRIPTION("DT driver for Denali NAND controller"); |