1 /* 2 * EIM driver for Freescale's i.MX chips 3 * 4 * Copyright (C) 2013 Freescale Semiconductor, Inc. 5 * 6 * This file is licensed under the terms of the GNU General Public 7 * License version 2. This program is licensed "as is" without any 8 * warranty of any kind, whether express or implied. 9 */ 10 #include <linux/module.h> 11 #include <linux/clk.h> 12 #include <linux/io.h> 13 #include <linux/of_address.h> 14 #include <linux/of.h> 15 #include <linux/of_platform.h> 16 #include <linux/platform_device.h> 17 #include <linux/property.h> 18 #include <linux/mfd/syscon.h> 19 #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h> 20 #include <linux/regmap.h> 21 22 struct imx_weim_devtype { 23 unsigned int cs_count; 24 unsigned int cs_regs_count; 25 unsigned int cs_stride; 26 unsigned int wcr_offset; 27 unsigned int wcr_bcm; 28 unsigned int wcr_cont_bclk; 29 }; 30 31 static const struct imx_weim_devtype imx1_weim_devtype = { 32 .cs_count = 6, 33 .cs_regs_count = 2, 34 .cs_stride = 0x08, 35 }; 36 37 static const struct imx_weim_devtype imx27_weim_devtype = { 38 .cs_count = 6, 39 .cs_regs_count = 3, 40 .cs_stride = 0x10, 41 }; 42 43 static const struct imx_weim_devtype imx50_weim_devtype = { 44 .cs_count = 4, 45 .cs_regs_count = 6, 46 .cs_stride = 0x18, 47 .wcr_offset = 0x90, 48 .wcr_bcm = BIT(0), 49 .wcr_cont_bclk = BIT(3), 50 }; 51 52 static const struct imx_weim_devtype imx51_weim_devtype = { 53 .cs_count = 6, 54 .cs_regs_count = 6, 55 .cs_stride = 0x18, 56 }; 57 58 #define MAX_CS_REGS_COUNT 6 59 #define MAX_CS_COUNT 6 60 #define OF_REG_SIZE 3 61 62 struct cs_timing { 63 bool is_applied; 64 u32 regs[MAX_CS_REGS_COUNT]; 65 }; 66 67 struct cs_timing_state { 68 struct cs_timing cs[MAX_CS_COUNT]; 69 }; 70 71 struct weim_priv { 72 void __iomem *base; 73 struct cs_timing_state timing_state; 74 }; 75 76 static const struct of_device_id weim_id_table[] = { 77 /* i.MX1/21 */ 78 { .compatible = "fsl,imx1-weim", .data = &imx1_weim_devtype, }, 79 /* i.MX25/27/31/35 */ 80 { .compatible = "fsl,imx27-weim", .data = &imx27_weim_devtype, }, 81 /* i.MX50/53/6Q */ 82 { .compatible = "fsl,imx50-weim", .data = &imx50_weim_devtype, }, 83 { .compatible = "fsl,imx6q-weim", .data = &imx50_weim_devtype, }, 84 /* i.MX51 */ 85 { .compatible = "fsl,imx51-weim", .data = &imx51_weim_devtype, }, 86 { } 87 }; 88 MODULE_DEVICE_TABLE(of, weim_id_table); 89 90 static int imx_weim_gpr_setup(struct platform_device *pdev) 91 { 92 struct device_node *np = pdev->dev.of_node; 93 struct of_range_parser parser; 94 struct of_range range; 95 struct regmap *gpr; 96 u32 gprvals[4] = { 97 05, /* CS0(128M) CS1(0M) CS2(0M) CS3(0M) */ 98 033, /* CS0(64M) CS1(64M) CS2(0M) CS3(0M) */ 99 0113, /* CS0(64M) CS1(32M) CS2(32M) CS3(0M) */ 100 01111, /* CS0(32M) CS1(32M) CS2(32M) CS3(32M) */ 101 }; 102 u32 gprval = 0; 103 u32 val; 104 int cs = 0; 105 int i = 0; 106 107 gpr = syscon_regmap_lookup_by_phandle(np, "fsl,weim-cs-gpr"); 108 if (IS_ERR(gpr)) { 109 dev_dbg(&pdev->dev, "failed to find weim-cs-gpr\n"); 110 return 0; 111 } 112 113 if (of_range_parser_init(&parser, np)) 114 goto err; 115 116 for_each_of_range(&parser, &range) { 117 cs = range.bus_addr >> 32; 118 val = (range.size / SZ_32M) | 1; 119 gprval |= val << cs * 3; 120 i++; 121 } 122 123 if (i == 0) 124 goto err; 125 126 for (i = 0; i < ARRAY_SIZE(gprvals); i++) { 127 if (gprval == gprvals[i]) { 128 /* Found it. Set up IOMUXC_GPR1[11:0] with it. */ 129 regmap_update_bits(gpr, IOMUXC_GPR1, 0xfff, gprval); 130 return 0; 131 } 132 } 133 134 err: 135 dev_err(&pdev->dev, "Invalid 'ranges' configuration\n"); 136 return -EINVAL; 137 } 138 139 /* Parse and set the timing for this device. */ 140 static int weim_timing_setup(struct device *dev, struct device_node *np, 141 const struct imx_weim_devtype *devtype) 142 { 143 u32 cs_idx, value[MAX_CS_REGS_COUNT]; 144 int i, ret; 145 int reg_idx, num_regs; 146 struct cs_timing *cst; 147 struct weim_priv *priv; 148 struct cs_timing_state *ts; 149 void __iomem *base; 150 151 if (WARN_ON(devtype->cs_regs_count > MAX_CS_REGS_COUNT)) 152 return -EINVAL; 153 if (WARN_ON(devtype->cs_count > MAX_CS_COUNT)) 154 return -EINVAL; 155 156 priv = dev_get_drvdata(dev); 157 base = priv->base; 158 ts = &priv->timing_state; 159 160 ret = of_property_read_u32_array(np, "fsl,weim-cs-timing", 161 value, devtype->cs_regs_count); 162 if (ret) 163 return ret; 164 165 /* 166 * the child node's "reg" property may contain multiple address ranges, 167 * extract the chip select for each. 168 */ 169 num_regs = of_property_count_elems_of_size(np, "reg", OF_REG_SIZE); 170 if (num_regs < 0) 171 return num_regs; 172 if (!num_regs) 173 return -EINVAL; 174 for (reg_idx = 0; reg_idx < num_regs; reg_idx++) { 175 /* get the CS index from this child node's "reg" property. */ 176 ret = of_property_read_u32_index(np, "reg", 177 reg_idx * OF_REG_SIZE, &cs_idx); 178 if (ret) 179 break; 180 181 if (cs_idx >= devtype->cs_count) 182 return -EINVAL; 183 184 /* prevent re-configuring a CS that's already been configured */ 185 cst = &ts->cs[cs_idx]; 186 if (cst->is_applied && memcmp(value, cst->regs, 187 devtype->cs_regs_count * sizeof(u32))) { 188 dev_err(dev, "fsl,weim-cs-timing conflict on %pOF", np); 189 return -EINVAL; 190 } 191 192 /* set the timing for WEIM */ 193 for (i = 0; i < devtype->cs_regs_count; i++) 194 writel(value[i], 195 base + cs_idx * devtype->cs_stride + i * 4); 196 if (!cst->is_applied) { 197 cst->is_applied = true; 198 memcpy(cst->regs, value, 199 devtype->cs_regs_count * sizeof(u32)); 200 } 201 } 202 203 return 0; 204 } 205 206 static int weim_parse_dt(struct platform_device *pdev) 207 { 208 const struct imx_weim_devtype *devtype = device_get_match_data(&pdev->dev); 209 int ret = 0, have_child = 0; 210 struct device_node *child; 211 struct weim_priv *priv; 212 void __iomem *base; 213 u32 reg; 214 215 if (devtype == &imx50_weim_devtype) { 216 ret = imx_weim_gpr_setup(pdev); 217 if (ret) 218 return ret; 219 } 220 221 priv = dev_get_drvdata(&pdev->dev); 222 base = priv->base; 223 224 if (of_property_read_bool(pdev->dev.of_node, "fsl,burst-clk-enable")) { 225 if (devtype->wcr_bcm) { 226 reg = readl(base + devtype->wcr_offset); 227 reg |= devtype->wcr_bcm; 228 229 if (of_property_read_bool(pdev->dev.of_node, 230 "fsl,continuous-burst-clk")) { 231 if (devtype->wcr_cont_bclk) { 232 reg |= devtype->wcr_cont_bclk; 233 } else { 234 dev_err(&pdev->dev, 235 "continuous burst clk not supported.\n"); 236 return -EINVAL; 237 } 238 } 239 240 writel(reg, base + devtype->wcr_offset); 241 } else { 242 dev_err(&pdev->dev, "burst clk mode not supported.\n"); 243 return -EINVAL; 244 } 245 } 246 247 for_each_available_child_of_node(pdev->dev.of_node, child) { 248 ret = weim_timing_setup(&pdev->dev, child, devtype); 249 if (ret) 250 dev_warn(&pdev->dev, "%pOF set timing failed.\n", 251 child); 252 else 253 have_child = 1; 254 } 255 256 if (have_child) 257 ret = of_platform_default_populate(pdev->dev.of_node, 258 NULL, &pdev->dev); 259 if (ret) 260 dev_err(&pdev->dev, "%pOF fail to create devices.\n", 261 pdev->dev.of_node); 262 return ret; 263 } 264 265 static int weim_probe(struct platform_device *pdev) 266 { 267 struct weim_priv *priv; 268 struct clk *clk; 269 void __iomem *base; 270 int ret; 271 272 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 273 if (!priv) 274 return -ENOMEM; 275 276 /* get the resource */ 277 base = devm_platform_ioremap_resource(pdev, 0); 278 if (IS_ERR(base)) 279 return PTR_ERR(base); 280 281 priv->base = base; 282 dev_set_drvdata(&pdev->dev, priv); 283 284 /* get the clock */ 285 clk = devm_clk_get_enabled(&pdev->dev, NULL); 286 if (IS_ERR(clk)) 287 return PTR_ERR(clk); 288 289 /* parse the device node */ 290 ret = weim_parse_dt(pdev); 291 if (ret) 292 return ret; 293 294 dev_info(&pdev->dev, "Driver registered.\n"); 295 296 return 0; 297 } 298 299 #if IS_ENABLED(CONFIG_OF_DYNAMIC) 300 static int of_weim_notify(struct notifier_block *nb, unsigned long action, 301 void *arg) 302 { 303 const struct imx_weim_devtype *devtype; 304 struct of_reconfig_data *rd = arg; 305 const struct of_device_id *of_id; 306 struct platform_device *pdev; 307 int ret = NOTIFY_OK; 308 309 switch (of_reconfig_get_state_change(action, rd)) { 310 case OF_RECONFIG_CHANGE_ADD: 311 of_id = of_match_node(weim_id_table, rd->dn->parent); 312 if (!of_id) 313 return NOTIFY_OK; /* not for us */ 314 315 devtype = of_id->data; 316 317 pdev = of_find_device_by_node(rd->dn->parent); 318 if (!pdev) { 319 pr_err("%s: could not find platform device for '%pOF'\n", 320 __func__, rd->dn->parent); 321 322 return notifier_from_errno(-EINVAL); 323 } 324 325 if (weim_timing_setup(&pdev->dev, rd->dn, devtype)) 326 dev_warn(&pdev->dev, 327 "Failed to setup timing for '%pOF'\n", rd->dn); 328 329 if (!of_node_check_flag(rd->dn, OF_POPULATED)) { 330 /* 331 * Clear the flag before adding the device so that 332 * fw_devlink doesn't skip adding consumers to this 333 * device. 334 */ 335 rd->dn->fwnode.flags &= ~FWNODE_FLAG_NOT_DEVICE; 336 if (!of_platform_device_create(rd->dn, NULL, &pdev->dev)) { 337 dev_err(&pdev->dev, 338 "Failed to create child device '%pOF'\n", 339 rd->dn); 340 ret = notifier_from_errno(-EINVAL); 341 } 342 } 343 344 platform_device_put(pdev); 345 346 break; 347 case OF_RECONFIG_CHANGE_REMOVE: 348 if (!of_node_check_flag(rd->dn, OF_POPULATED)) 349 return NOTIFY_OK; /* device already destroyed */ 350 351 of_id = of_match_node(weim_id_table, rd->dn->parent); 352 if (!of_id) 353 return NOTIFY_OK; /* not for us */ 354 355 pdev = of_find_device_by_node(rd->dn); 356 if (!pdev) { 357 pr_err("Could not find platform device for '%pOF'\n", 358 rd->dn); 359 360 ret = notifier_from_errno(-EINVAL); 361 } else { 362 of_platform_device_destroy(&pdev->dev, NULL); 363 platform_device_put(pdev); 364 } 365 366 break; 367 default: 368 break; 369 } 370 371 return ret; 372 } 373 374 static struct notifier_block weim_of_notifier = { 375 .notifier_call = of_weim_notify, 376 }; 377 #endif /* IS_ENABLED(CONFIG_OF_DYNAMIC) */ 378 379 static struct platform_driver weim_driver = { 380 .driver = { 381 .name = "imx-weim", 382 .of_match_table = weim_id_table, 383 }, 384 .probe = weim_probe, 385 }; 386 387 static int __init weim_init(void) 388 { 389 #if IS_ENABLED(CONFIG_OF_DYNAMIC) 390 WARN_ON(of_reconfig_notifier_register(&weim_of_notifier)); 391 #endif /* IS_ENABLED(CONFIG_OF_DYNAMIC) */ 392 393 return platform_driver_register(&weim_driver); 394 } 395 module_init(weim_init); 396 397 static void __exit weim_exit(void) 398 { 399 #if IS_ENABLED(CONFIG_OF_DYNAMIC) 400 of_reconfig_notifier_unregister(&weim_of_notifier); 401 #endif /* IS_ENABLED(CONFIG_OF_DYNAMIC) */ 402 403 return platform_driver_unregister(&weim_driver); 404 405 } 406 module_exit(weim_exit); 407 408 MODULE_AUTHOR("Freescale Semiconductor Inc."); 409 MODULE_DESCRIPTION("i.MX EIM Controller Driver"); 410 MODULE_LICENSE("GPL"); 411