aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap2/gpmc.c
diff options
context:
space:
mode:
authorDaniel Mack <zonque@gmail.com>2012-12-14 05:36:44 -0500
committerTony Lindgren <tony@atomide.com>2013-01-15 17:50:15 -0500
commitbc6b1e7b86f5d8e4a6fc1c0189e64bba4077efe0 (patch)
treeddf01fdfc247be244e453139a10af05c7b50b602 /arch/arm/mach-omap2/gpmc.c
parentf50a0380897d2a5e61b251b07c50ee48fa298cfd (diff)
ARM: OMAP: gpmc: add DT bindings for GPMC timings and NAND
This patch adds basic DT bindings for OMAP GPMC. The actual peripherals are instantiated from child nodes within the GPMC node, and the only type of device that is currently supported is NAND. Code was added to parse the generic GPMC timing parameters and some documentation with examples on how to use them. Successfully tested on an AM33xx board. Signed-off-by: Daniel Mack <zonque@gmail.com> Acked-by: Grant Likely <grant.likely@secretlab.ca> [tony@atomide.com: updated to apply] Signed-off-by: Tony Lindgren <tony@atomide.com>
Diffstat (limited to 'arch/arm/mach-omap2/gpmc.c')
-rw-r--r--arch/arm/mach-omap2/gpmc.c173
1 files changed, 173 insertions, 0 deletions
diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 1f0ec79aabf1..01ce462e265d 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -25,6 +25,10 @@
25#include <linux/module.h> 25#include <linux/module.h>
26#include <linux/interrupt.h> 26#include <linux/interrupt.h>
27#include <linux/platform_device.h> 27#include <linux/platform_device.h>
28#include <linux/of.h>
29#include <linux/of_mtd.h>
30#include <linux/of_device.h>
31#include <linux/mtd/nand.h>
28 32
29#include <linux/platform_data/mtd-nand-omap2.h> 33#include <linux/platform_data/mtd-nand-omap2.h>
30 34
@@ -34,6 +38,7 @@
34#include "common.h" 38#include "common.h"
35#include "omap_device.h" 39#include "omap_device.h"
36#include "gpmc.h" 40#include "gpmc.h"
41#include "gpmc-nand.h"
37 42
38#define DEVICE_NAME "omap-gpmc" 43#define DEVICE_NAME "omap-gpmc"
39 44
@@ -1121,6 +1126,165 @@ int gpmc_calc_timings(struct gpmc_timings *gpmc_t,
1121 return 0; 1126 return 0;
1122} 1127}
1123 1128
1129#ifdef CONFIG_OF
1130static struct of_device_id gpmc_dt_ids[] = {
1131 { .compatible = "ti,omap2420-gpmc" },
1132 { .compatible = "ti,omap2430-gpmc" },
1133 { .compatible = "ti,omap3430-gpmc" }, /* omap3430 & omap3630 */
1134 { .compatible = "ti,omap4430-gpmc" }, /* omap4430 & omap4460 & omap543x */
1135 { .compatible = "ti,am3352-gpmc" }, /* am335x devices */
1136 { }
1137};
1138MODULE_DEVICE_TABLE(of, gpmc_dt_ids);
1139
1140static void __maybe_unused gpmc_read_timings_dt(struct device_node *np,
1141 struct gpmc_timings *gpmc_t)
1142{
1143 u32 val;
1144
1145 memset(gpmc_t, 0, sizeof(*gpmc_t));
1146
1147 /* minimum clock period for syncronous mode */
1148 if (!of_property_read_u32(np, "gpmc,sync-clk", &val))
1149 gpmc_t->sync_clk = val;
1150
1151 /* chip select timtings */
1152 if (!of_property_read_u32(np, "gpmc,cs-on", &val))
1153 gpmc_t->cs_on = val;
1154
1155 if (!of_property_read_u32(np, "gpmc,cs-rd-off", &val))
1156 gpmc_t->cs_rd_off = val;
1157
1158 if (!of_property_read_u32(np, "gpmc,cs-wr-off", &val))
1159 gpmc_t->cs_wr_off = val;
1160
1161 /* ADV signal timings */
1162 if (!of_property_read_u32(np, "gpmc,adv-on", &val))
1163 gpmc_t->adv_on = val;
1164
1165 if (!of_property_read_u32(np, "gpmc,adv-rd-off", &val))
1166 gpmc_t->adv_rd_off = val;
1167
1168 if (!of_property_read_u32(np, "gpmc,adv-wr-off", &val))
1169 gpmc_t->adv_wr_off = val;
1170
1171 /* WE signal timings */
1172 if (!of_property_read_u32(np, "gpmc,we-on", &val))
1173 gpmc_t->we_on = val;
1174
1175 if (!of_property_read_u32(np, "gpmc,we-off", &val))
1176 gpmc_t->we_off = val;
1177
1178 /* OE signal timings */
1179 if (!of_property_read_u32(np, "gpmc,oe-on", &val))
1180 gpmc_t->oe_on = val;
1181
1182 if (!of_property_read_u32(np, "gpmc,oe-off", &val))
1183 gpmc_t->oe_off = val;
1184
1185 /* access and cycle timings */
1186 if (!of_property_read_u32(np, "gpmc,page-burst-access", &val))
1187 gpmc_t->page_burst_access = val;
1188
1189 if (!of_property_read_u32(np, "gpmc,access", &val))
1190 gpmc_t->access = val;
1191
1192 if (!of_property_read_u32(np, "gpmc,rd-cycle", &val))
1193 gpmc_t->rd_cycle = val;
1194
1195 if (!of_property_read_u32(np, "gpmc,wr-cycle", &val))
1196 gpmc_t->wr_cycle = val;
1197
1198 /* only for OMAP3430 */
1199 if (!of_property_read_u32(np, "gpmc,wr-access", &val))
1200 gpmc_t->wr_access = val;
1201
1202 if (!of_property_read_u32(np, "gpmc,wr-data-mux-bus", &val))
1203 gpmc_t->wr_data_mux_bus = val;
1204}
1205
1206#ifdef CONFIG_MTD_NAND
1207
1208static const char * const nand_ecc_opts[] = {
1209 [OMAP_ECC_HAMMING_CODE_DEFAULT] = "sw",
1210 [OMAP_ECC_HAMMING_CODE_HW] = "hw",
1211 [OMAP_ECC_HAMMING_CODE_HW_ROMCODE] = "hw-romcode",
1212 [OMAP_ECC_BCH4_CODE_HW] = "bch4",
1213 [OMAP_ECC_BCH8_CODE_HW] = "bch8",
1214};
1215
1216static int gpmc_probe_nand_child(struct platform_device *pdev,
1217 struct device_node *child)
1218{
1219 u32 val;
1220 const char *s;
1221 struct gpmc_timings gpmc_t;
1222 struct omap_nand_platform_data *gpmc_nand_data;
1223
1224 if (of_property_read_u32(child, "reg", &val) < 0) {
1225 dev_err(&pdev->dev, "%s has no 'reg' property\n",
1226 child->full_name);
1227 return -ENODEV;
1228 }
1229
1230 gpmc_nand_data = devm_kzalloc(&pdev->dev, sizeof(*gpmc_nand_data),
1231 GFP_KERNEL);
1232 if (!gpmc_nand_data)
1233 return -ENOMEM;
1234
1235 gpmc_nand_data->cs = val;
1236 gpmc_nand_data->of_node = child;
1237
1238 if (!of_property_read_string(child, "ti,nand-ecc-opt", &s))
1239 for (val = 0; val < ARRAY_SIZE(nand_ecc_opts); val++)
1240 if (!strcasecmp(s, nand_ecc_opts[val])) {
1241 gpmc_nand_data->ecc_opt = val;
1242 break;
1243 }
1244
1245 val = of_get_nand_bus_width(child);
1246 if (val == 16)
1247 gpmc_nand_data->devsize = NAND_BUSWIDTH_16;
1248
1249 gpmc_read_timings_dt(child, &gpmc_t);
1250 gpmc_nand_init(gpmc_nand_data, &gpmc_t);
1251
1252 return 0;
1253}
1254#else
1255static int gpmc_probe_nand_child(struct platform_device *pdev,
1256 struct device_node *child)
1257{
1258 return 0;
1259}
1260#endif
1261
1262static int gpmc_probe_dt(struct platform_device *pdev)
1263{
1264 int ret;
1265 struct device_node *child;
1266 const struct of_device_id *of_id =
1267 of_match_device(gpmc_dt_ids, &pdev->dev);
1268
1269 if (!of_id)
1270 return 0;
1271
1272 for_each_node_by_name(child, "nand") {
1273 ret = gpmc_probe_nand_child(pdev, child);
1274 of_node_put(child);
1275 if (ret < 0)
1276 return ret;
1277 }
1278
1279 return 0;
1280}
1281#else
1282static int gpmc_probe_dt(struct platform_device *pdev)
1283{
1284 return 0;
1285}
1286#endif
1287
1124static int gpmc_probe(struct platform_device *pdev) 1288static int gpmc_probe(struct platform_device *pdev)
1125{ 1289{
1126 int rc; 1290 int rc;
@@ -1174,6 +1338,14 @@ static int gpmc_probe(struct platform_device *pdev)
1174 if (IS_ERR_VALUE(gpmc_setup_irq())) 1338 if (IS_ERR_VALUE(gpmc_setup_irq()))
1175 dev_warn(gpmc_dev, "gpmc_setup_irq failed\n"); 1339 dev_warn(gpmc_dev, "gpmc_setup_irq failed\n");
1176 1340
1341 rc = gpmc_probe_dt(pdev);
1342 if (rc < 0) {
1343 clk_disable_unprepare(gpmc_l3_clk);
1344 clk_put(gpmc_l3_clk);
1345 dev_err(gpmc_dev, "failed to probe DT parameters\n");
1346 return rc;
1347 }
1348
1177 return 0; 1349 return 0;
1178} 1350}
1179 1351
@@ -1191,6 +1363,7 @@ static struct platform_driver gpmc_driver = {
1191 .driver = { 1363 .driver = {
1192 .name = DEVICE_NAME, 1364 .name = DEVICE_NAME,
1193 .owner = THIS_MODULE, 1365 .owner = THIS_MODULE,
1366 .of_match_table = of_match_ptr(gpmc_dt_ids),
1194 }, 1367 },
1195}; 1368};
1196 1369