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 | */ |
Masahiro Yamada | da4734b | 2017-09-22 12:46:40 +0900 | [diff] [blame] | 15 | |
Dinh Nguyen | 30f9f2f | 2012-09-27 10:58:06 -0600 | [diff] [blame] | 16 | #include <linux/clk.h> |
| 17 | #include <linux/err.h> |
| 18 | #include <linux/io.h> |
| 19 | #include <linux/ioport.h> |
| 20 | #include <linux/kernel.h> |
| 21 | #include <linux/module.h> |
Dinh Nguyen | 30f9f2f | 2012-09-27 10:58:06 -0600 | [diff] [blame] | 22 | #include <linux/of.h> |
| 23 | #include <linux/of_device.h> |
Masahiro Yamada | da4734b | 2017-09-22 12:46:40 +0900 | [diff] [blame] | 24 | #include <linux/platform_device.h> |
Dinh Nguyen | 30f9f2f | 2012-09-27 10:58:06 -0600 | [diff] [blame] | 25 | |
| 26 | #include "denali.h" |
| 27 | |
| 28 | struct denali_dt { |
| 29 | struct denali_nand_info denali; |
| 30 | struct clk *clk; |
| 31 | }; |
| 32 | |
Masahiro Yamada | be72a4a | 2017-03-23 05:07:07 +0900 | [diff] [blame] | 33 | struct denali_dt_data { |
Masahiro Yamada | e7beeee | 2017-03-30 15:45:57 +0900 | [diff] [blame] | 34 | unsigned int revision; |
Masahiro Yamada | be72a4a | 2017-03-23 05:07:07 +0900 | [diff] [blame] | 35 | unsigned int caps; |
Masahiro Yamada | 7de117f | 2017-06-07 20:52:12 +0900 | [diff] [blame] | 36 | const struct nand_ecc_caps *ecc_caps; |
Masahiro Yamada | be72a4a | 2017-03-23 05:07:07 +0900 | [diff] [blame] | 37 | }; |
| 38 | |
Masahiro Yamada | 7de117f | 2017-06-07 20:52:12 +0900 | [diff] [blame] | 39 | NAND_ECC_CAPS_SINGLE(denali_socfpga_ecc_caps, denali_calc_ecc_bytes, |
| 40 | 512, 8, 15); |
Masahiro Yamada | a56609c | 2017-03-30 15:45:53 +0900 | [diff] [blame] | 41 | static const struct denali_dt_data denali_socfpga_data = { |
| 42 | .caps = DENALI_CAP_HW_ECC_FIXUP, |
Masahiro Yamada | 7de117f | 2017-06-07 20:52:12 +0900 | [diff] [blame] | 43 | .ecc_caps = &denali_socfpga_ecc_caps, |
Masahiro Yamada | a56609c | 2017-03-30 15:45:53 +0900 | [diff] [blame] | 44 | }; |
Dinh Nguyen | 30f9f2f | 2012-09-27 10:58:06 -0600 | [diff] [blame] | 45 | |
Masahiro Yamada | 91300dd | 2017-06-07 20:52:14 +0900 | [diff] [blame] | 46 | NAND_ECC_CAPS_SINGLE(denali_uniphier_v5a_ecc_caps, denali_calc_ecc_bytes, |
| 47 | 1024, 8, 16, 24); |
| 48 | static const struct denali_dt_data denali_uniphier_v5a_data = { |
| 49 | .caps = DENALI_CAP_HW_ECC_FIXUP | |
| 50 | DENALI_CAP_DMA_64BIT, |
| 51 | .ecc_caps = &denali_uniphier_v5a_ecc_caps, |
| 52 | }; |
| 53 | |
| 54 | NAND_ECC_CAPS_SINGLE(denali_uniphier_v5b_ecc_caps, denali_calc_ecc_bytes, |
| 55 | 1024, 8, 16); |
| 56 | static const struct denali_dt_data denali_uniphier_v5b_data = { |
| 57 | .revision = 0x0501, |
| 58 | .caps = DENALI_CAP_HW_ECC_FIXUP | |
| 59 | DENALI_CAP_DMA_64BIT, |
| 60 | .ecc_caps = &denali_uniphier_v5b_ecc_caps, |
| 61 | }; |
| 62 | |
Masahiro Yamada | a56609c | 2017-03-30 15:45:53 +0900 | [diff] [blame] | 63 | static const struct of_device_id denali_nand_dt_ids[] = { |
| 64 | { |
| 65 | .compatible = "altr,socfpga-denali-nand", |
| 66 | .data = &denali_socfpga_data, |
| 67 | }, |
Masahiro Yamada | 91300dd | 2017-06-07 20:52:14 +0900 | [diff] [blame] | 68 | { |
| 69 | .compatible = "socionext,uniphier-denali-nand-v5a", |
| 70 | .data = &denali_uniphier_v5a_data, |
| 71 | }, |
| 72 | { |
| 73 | .compatible = "socionext,uniphier-denali-nand-v5b", |
| 74 | .data = &denali_uniphier_v5b_data, |
| 75 | }, |
Masahiro Yamada | a56609c | 2017-03-30 15:45:53 +0900 | [diff] [blame] | 76 | { /* sentinel */ } |
| 77 | }; |
Dinh Nguyen | 30f9f2f | 2012-09-27 10:58:06 -0600 | [diff] [blame] | 78 | MODULE_DEVICE_TABLE(of, denali_nand_dt_ids); |
| 79 | |
Masahiro Yamada | 3f5c358 | 2017-03-30 15:45:56 +0900 | [diff] [blame] | 80 | static int denali_dt_probe(struct platform_device *pdev) |
Dinh Nguyen | 30f9f2f | 2012-09-27 10:58:06 -0600 | [diff] [blame] | 81 | { |
Masahiro Yamada | 2b8c92b | 2017-06-06 08:21:40 +0900 | [diff] [blame] | 82 | struct resource *res; |
Dinh Nguyen | 30f9f2f | 2012-09-27 10:58:06 -0600 | [diff] [blame] | 83 | struct denali_dt *dt; |
Masahiro Yamada | be72a4a | 2017-03-23 05:07:07 +0900 | [diff] [blame] | 84 | const struct denali_dt_data *data; |
Dinh Nguyen | 30f9f2f | 2012-09-27 10:58:06 -0600 | [diff] [blame] | 85 | struct denali_nand_info *denali; |
| 86 | int ret; |
Dinh Nguyen | 30f9f2f | 2012-09-27 10:58:06 -0600 | [diff] [blame] | 87 | |
Masahiro Yamada | 3f5c358 | 2017-03-30 15:45:56 +0900 | [diff] [blame] | 88 | dt = devm_kzalloc(&pdev->dev, sizeof(*dt), GFP_KERNEL); |
Dinh Nguyen | 30f9f2f | 2012-09-27 10:58:06 -0600 | [diff] [blame] | 89 | if (!dt) |
| 90 | return -ENOMEM; |
| 91 | denali = &dt->denali; |
| 92 | |
Masahiro Yamada | 3f5c358 | 2017-03-30 15:45:56 +0900 | [diff] [blame] | 93 | data = of_device_get_match_data(&pdev->dev); |
Masahiro Yamada | e7beeee | 2017-03-30 15:45:57 +0900 | [diff] [blame] | 94 | if (data) { |
| 95 | denali->revision = data->revision; |
Masahiro Yamada | be72a4a | 2017-03-23 05:07:07 +0900 | [diff] [blame] | 96 | denali->caps = data->caps; |
Masahiro Yamada | 7de117f | 2017-06-07 20:52:12 +0900 | [diff] [blame] | 97 | denali->ecc_caps = data->ecc_caps; |
Masahiro Yamada | e7beeee | 2017-03-30 15:45:57 +0900 | [diff] [blame] | 98 | } |
Masahiro Yamada | be72a4a | 2017-03-23 05:07:07 +0900 | [diff] [blame] | 99 | |
Masahiro Yamada | 3f5c358 | 2017-03-30 15:45:56 +0900 | [diff] [blame] | 100 | denali->dev = &pdev->dev; |
| 101 | denali->irq = platform_get_irq(pdev, 0); |
Dinh Nguyen | 30f9f2f | 2012-09-27 10:58:06 -0600 | [diff] [blame] | 102 | if (denali->irq < 0) { |
Masahiro Yamada | 3f5c358 | 2017-03-30 15:45:56 +0900 | [diff] [blame] | 103 | dev_err(&pdev->dev, "no irq defined\n"); |
Sachin Kamat | 2f2ff14 | 2013-03-18 15:11:13 +0530 | [diff] [blame] | 104 | return denali->irq; |
Dinh Nguyen | 30f9f2f | 2012-09-27 10:58:06 -0600 | [diff] [blame] | 105 | } |
| 106 | |
Masahiro Yamada | 2b8c92b | 2017-06-06 08:21:40 +0900 | [diff] [blame] | 107 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "denali_reg"); |
Masahiro Yamada | 0d3a966 | 2017-06-16 14:36:39 +0900 | [diff] [blame] | 108 | denali->reg = devm_ioremap_resource(&pdev->dev, res); |
| 109 | if (IS_ERR(denali->reg)) |
| 110 | return PTR_ERR(denali->reg); |
Dinh Nguyen | 30f9f2f | 2012-09-27 10:58:06 -0600 | [diff] [blame] | 111 | |
Masahiro Yamada | 2b8c92b | 2017-06-06 08:21:40 +0900 | [diff] [blame] | 112 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_data"); |
Masahiro Yamada | 0d3a966 | 2017-06-16 14:36:39 +0900 | [diff] [blame] | 113 | denali->host = devm_ioremap_resource(&pdev->dev, res); |
| 114 | if (IS_ERR(denali->host)) |
| 115 | return PTR_ERR(denali->host); |
Dinh Nguyen | 30f9f2f | 2012-09-27 10:58:06 -0600 | [diff] [blame] | 116 | |
Masahiro Yamada | 3f5c358 | 2017-03-30 15:45:56 +0900 | [diff] [blame] | 117 | dt->clk = devm_clk_get(&pdev->dev, NULL); |
Dinh Nguyen | 30f9f2f | 2012-09-27 10:58:06 -0600 | [diff] [blame] | 118 | if (IS_ERR(dt->clk)) { |
Masahiro Yamada | 3f5c358 | 2017-03-30 15:45:56 +0900 | [diff] [blame] | 119 | dev_err(&pdev->dev, "no clk available\n"); |
Dinh Nguyen | 30f9f2f | 2012-09-27 10:58:06 -0600 | [diff] [blame] | 120 | return PTR_ERR(dt->clk); |
| 121 | } |
Arvind Yadav | c044179 | 2017-08-01 17:05:09 +0530 | [diff] [blame] | 122 | ret = clk_prepare_enable(dt->clk); |
| 123 | if (ret) |
| 124 | return ret; |
Dinh Nguyen | 30f9f2f | 2012-09-27 10:58:06 -0600 | [diff] [blame] | 125 | |
Masahiro Yamada | 3f6e698 | 2018-06-23 01:06:34 +0900 | [diff] [blame] | 126 | /* |
| 127 | * Hardcode the clock rate for the backward compatibility. |
| 128 | * This works for both SOCFPGA and UniPhier. |
| 129 | */ |
| 130 | denali->clk_x_rate = 200000000; |
Masahiro Yamada | 1bb8866 | 2017-06-13 22:45:37 +0900 | [diff] [blame] | 131 | |
Dinh Nguyen | 30f9f2f | 2012-09-27 10:58:06 -0600 | [diff] [blame] | 132 | ret = denali_init(denali); |
| 133 | if (ret) |
| 134 | goto out_disable_clk; |
| 135 | |
Masahiro Yamada | 3f5c358 | 2017-03-30 15:45:56 +0900 | [diff] [blame] | 136 | platform_set_drvdata(pdev, dt); |
Dinh Nguyen | 30f9f2f | 2012-09-27 10:58:06 -0600 | [diff] [blame] | 137 | return 0; |
| 138 | |
| 139 | out_disable_clk: |
| 140 | clk_disable_unprepare(dt->clk); |
Dinh Nguyen | 30f9f2f | 2012-09-27 10:58:06 -0600 | [diff] [blame] | 141 | |
| 142 | return ret; |
| 143 | } |
| 144 | |
Masahiro Yamada | 3f5c358 | 2017-03-30 15:45:56 +0900 | [diff] [blame] | 145 | static int denali_dt_remove(struct platform_device *pdev) |
Dinh Nguyen | 30f9f2f | 2012-09-27 10:58:06 -0600 | [diff] [blame] | 146 | { |
Masahiro Yamada | 3f5c358 | 2017-03-30 15:45:56 +0900 | [diff] [blame] | 147 | struct denali_dt *dt = platform_get_drvdata(pdev); |
Dinh Nguyen | 30f9f2f | 2012-09-27 10:58:06 -0600 | [diff] [blame] | 148 | |
| 149 | denali_remove(&dt->denali); |
Masahiro Yamada | a1a2617 | 2016-11-03 02:21:04 +0900 | [diff] [blame] | 150 | clk_disable_unprepare(dt->clk); |
Dinh Nguyen | 30f9f2f | 2012-09-27 10:58:06 -0600 | [diff] [blame] | 151 | |
| 152 | return 0; |
| 153 | } |
| 154 | |
| 155 | static struct platform_driver denali_dt_driver = { |
| 156 | .probe = denali_dt_probe, |
Bill Pemberton | 5153b88 | 2012-11-19 13:21:24 -0500 | [diff] [blame] | 157 | .remove = denali_dt_remove, |
Dinh Nguyen | 30f9f2f | 2012-09-27 10:58:06 -0600 | [diff] [blame] | 158 | .driver = { |
| 159 | .name = "denali-nand-dt", |
Sachin Kamat | ef54f87 | 2013-03-18 15:11:14 +0530 | [diff] [blame] | 160 | .of_match_table = denali_nand_dt_ids, |
Dinh Nguyen | 30f9f2f | 2012-09-27 10:58:06 -0600 | [diff] [blame] | 161 | }, |
| 162 | }; |
Sachin Kamat | 82fc812 | 2013-03-18 15:11:12 +0530 | [diff] [blame] | 163 | module_platform_driver(denali_dt_driver); |
Dinh Nguyen | 30f9f2f | 2012-09-27 10:58:06 -0600 | [diff] [blame] | 164 | |
| 165 | MODULE_LICENSE("GPL"); |
| 166 | MODULE_AUTHOR("Jamie Iles"); |
| 167 | MODULE_DESCRIPTION("DT driver for Denali NAND controller"); |