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_device.h> 14 #include <linux/mfd/syscon.h> 15 #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h> 16 #include <linux/regmap.h> 17 18 struct imx_weim_devtype { 19 unsigned int cs_count; 20 unsigned int cs_regs_count; 21 unsigned int cs_stride; 22 unsigned int wcr_offset; 23 unsigned int wcr_bcm; 24 unsigned int wcr_cont_bclk; 25 }; 26 27 static const struct imx_weim_devtype imx1_weim_devtype = { 28 .cs_count = 6, 29 .cs_regs_count = 2, 30 .cs_stride = 0x08, 31 }; 32 33 static const struct imx_weim_devtype imx27_weim_devtype = { 34 .cs_count = 6, 35 .cs_regs_count = 3, 36 .cs_stride = 0x10, 37 }; 38 39 static const struct imx_weim_devtype imx50_weim_devtype = { 40 .cs_count = 4, 41 .cs_regs_count = 6, 42 .cs_stride = 0x18, 43 .wcr_offset = 0x90, 44 .wcr_bcm = BIT(0), 45 .wcr_cont_bclk = BIT(3), 46 }; 47 48 static const struct imx_weim_devtype imx51_weim_devtype = { 49 .cs_count = 6, 50 .cs_regs_count = 6, 51 .cs_stride = 0x18, 52 }; 53 54 #define MAX_CS_REGS_COUNT 6 55 #define MAX_CS_COUNT 6 56 #define OF_REG_SIZE 3 57 58 struct cs_timing { 59 bool is_applied; 60 u32 regs[MAX_CS_REGS_COUNT]; 61 }; 62 63 struct cs_timing_state { 64 struct cs_timing cs[MAX_CS_COUNT]; 65 }; 66 67 static const struct of_device_id weim_id_table[] = { 68 /* i.MX1/21 */ 69 { .compatible = "fsl,imx1-weim", .data = &imx1_weim_devtype, }, 70 /* i.MX25/27/31/35 */ 71 { .compatible = "fsl,imx27-weim", .data = &imx27_weim_devtype, }, 72 /* i.MX50/53/6Q */ 73 { .compatible = "fsl,imx50-weim", .data = &imx50_weim_devtype, }, 74 { .compatible = "fsl,imx6q-weim", .data = &imx50_weim_devtype, }, 75 /* i.MX51 */ 76 { .compatible = "fsl,imx51-weim", .data = &imx51_weim_devtype, }, 77 { } 78 }; 79 MODULE_DEVICE_TABLE(of, weim_id_table); 80 81 static int imx_weim_gpr_setup(struct platform_device *pdev) 82 { 83 struct device_node *np = pdev->dev.of_node; 84 struct property *prop; 85 const __be32 *p; 86 struct regmap *gpr; 87 u32 gprvals[4] = { 88 05, /* CS0(128M) CS1(0M) CS2(0M) CS3(0M) */ 89 033, /* CS0(64M) CS1(64M) CS2(0M) CS3(0M) */ 90 0113, /* CS0(64M) CS1(32M) CS2(32M) CS3(0M) */ 91 01111, /* CS0(32M) CS1(32M) CS2(32M) CS3(32M) */ 92 }; 93 u32 gprval = 0; 94 u32 val; 95 int cs = 0; 96 int i = 0; 97 98 gpr = syscon_regmap_lookup_by_phandle(np, "fsl,weim-cs-gpr"); 99 if (IS_ERR(gpr)) { 100 dev_dbg(&pdev->dev, "failed to find weim-cs-gpr\n"); 101 return 0; 102 } 103 104 of_property_for_each_u32(np, "ranges", prop, p, val) { 105 if (i % 4 == 0) { 106 cs = val; 107 } else if (i % 4 == 3 && val) { 108 val = (val / SZ_32M) | 1; 109 gprval |= val << cs * 3; 110 } 111 i++; 112 } 113 114 if (i == 0 || i % 4) 115 goto err; 116 117 for (i = 0; i < ARRAY_SIZE(gprvals); i++) { 118 if (gprval == gprvals[i]) { 119 /* Found it. Set up IOMUXC_GPR1[11:0] with it. */ 120 regmap_update_bits(gpr, IOMUXC_GPR1, 0xfff, gprval); 121 return 0; 122 } 123 } 124 125 err: 126 dev_err(&pdev->dev, "Invalid 'ranges' configuration\n"); 127 return -EINVAL; 128 } 129 130 /* Parse and set the timing for this device. */ 131 static int weim_timing_setup(struct device *dev, 132 struct device_node *np, void __iomem *base, 133 const struct imx_weim_devtype *devtype, 134 struct cs_timing_state *ts) 135 { 136 u32 cs_idx, value[MAX_CS_REGS_COUNT]; 137 int i, ret; 138 int reg_idx, num_regs; 139 struct cs_timing *cst; 140 141 if (WARN_ON(devtype->cs_regs_count > MAX_CS_REGS_COUNT)) 142 return -EINVAL; 143 if (WARN_ON(devtype->cs_count > MAX_CS_COUNT)) 144 return -EINVAL; 145 146 ret = of_property_read_u32_array(np, "fsl,weim-cs-timing", 147 value, devtype->cs_regs_count); 148 if (ret) 149 return ret; 150 151 /* 152 * the child node's "reg" property may contain multiple address ranges, 153 * extract the chip select for each. 154 */ 155 num_regs = of_property_count_elems_of_size(np, "reg", OF_REG_SIZE); 156 if (num_regs < 0) 157 return num_regs; 158 if (!num_regs) 159 return -EINVAL; 160 for (reg_idx = 0; reg_idx < num_regs; reg_idx++) { 161 /* get the CS index from this child node's "reg" property. */ 162 ret = of_property_read_u32_index(np, "reg", 163 reg_idx * OF_REG_SIZE, &cs_idx); 164 if (ret) 165 break; 166 167 if (cs_idx >= devtype->cs_count) 168 return -EINVAL; 169 170 /* prevent re-configuring a CS that's already been configured */ 171 cst = &ts->cs[cs_idx]; 172 if (cst->is_applied && memcmp(value, cst->regs, 173 devtype->cs_regs_count * sizeof(u32))) { 174 dev_err(dev, "fsl,weim-cs-timing conflict on %pOF", np); 175 return -EINVAL; 176 } 177 178 /* set the timing for WEIM */ 179 for (i = 0; i < devtype->cs_regs_count; i++) 180 writel(value[i], 181 base + cs_idx * devtype->cs_stride + i * 4); 182 if (!cst->is_applied) { 183 cst->is_applied = true; 184 memcpy(cst->regs, value, 185 devtype->cs_regs_count * sizeof(u32)); 186 } 187 } 188 189 return 0; 190 } 191 192 static int weim_parse_dt(struct platform_device *pdev, void __iomem *base) 193 { 194 const struct of_device_id *of_id = of_match_device(weim_id_table, 195 &pdev->dev); 196 const struct imx_weim_devtype *devtype = of_id->data; 197 struct device_node *child; 198 int ret, have_child = 0; 199 struct cs_timing_state ts = {}; 200 u32 reg; 201 202 if (devtype == &imx50_weim_devtype) { 203 ret = imx_weim_gpr_setup(pdev); 204 if (ret) 205 return ret; 206 } 207 208 if (of_property_read_bool(pdev->dev.of_node, "fsl,burst-clk-enable")) { 209 if (devtype->wcr_bcm) { 210 reg = readl(base + devtype->wcr_offset); 211 reg |= devtype->wcr_bcm; 212 213 if (of_property_read_bool(pdev->dev.of_node, 214 "fsl,continuous-burst-clk")) { 215 if (devtype->wcr_cont_bclk) { 216 reg |= devtype->wcr_cont_bclk; 217 } else { 218 dev_err(&pdev->dev, 219 "continuous burst clk not supported.\n"); 220 return -EINVAL; 221 } 222 } 223 224 writel(reg, base + devtype->wcr_offset); 225 } else { 226 dev_err(&pdev->dev, "burst clk mode not supported.\n"); 227 return -EINVAL; 228 } 229 } 230 231 for_each_available_child_of_node(pdev->dev.of_node, child) { 232 ret = weim_timing_setup(&pdev->dev, child, base, devtype, &ts); 233 if (ret) 234 dev_warn(&pdev->dev, "%pOF set timing failed.\n", 235 child); 236 else 237 have_child = 1; 238 } 239 240 if (have_child) 241 ret = of_platform_default_populate(pdev->dev.of_node, 242 NULL, &pdev->dev); 243 if (ret) 244 dev_err(&pdev->dev, "%pOF fail to create devices.\n", 245 pdev->dev.of_node); 246 return ret; 247 } 248 249 static int weim_probe(struct platform_device *pdev) 250 { 251 struct resource *res; 252 struct clk *clk; 253 void __iomem *base; 254 int ret; 255 256 /* get the resource */ 257 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 258 base = devm_ioremap_resource(&pdev->dev, res); 259 if (IS_ERR(base)) 260 return PTR_ERR(base); 261 262 /* get the clock */ 263 clk = devm_clk_get(&pdev->dev, NULL); 264 if (IS_ERR(clk)) 265 return PTR_ERR(clk); 266 267 ret = clk_prepare_enable(clk); 268 if (ret) 269 return ret; 270 271 /* parse the device node */ 272 ret = weim_parse_dt(pdev, base); 273 if (ret) 274 clk_disable_unprepare(clk); 275 else 276 dev_info(&pdev->dev, "Driver registered.\n"); 277 278 return ret; 279 } 280 281 static struct platform_driver weim_driver = { 282 .driver = { 283 .name = "imx-weim", 284 .of_match_table = weim_id_table, 285 }, 286 .probe = weim_probe, 287 }; 288 module_platform_driver(weim_driver); 289 290 MODULE_AUTHOR("Freescale Semiconductor Inc."); 291 MODULE_DESCRIPTION("i.MX EIM Controller Driver"); 292 MODULE_LICENSE("GPL"); 293