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 15 struct imx_weim_devtype { 16 unsigned int cs_count; 17 unsigned int cs_regs_count; 18 unsigned int cs_stride; 19 }; 20 21 static const struct imx_weim_devtype imx1_weim_devtype = { 22 .cs_count = 6, 23 .cs_regs_count = 2, 24 .cs_stride = 0x08, 25 }; 26 27 static const struct imx_weim_devtype imx27_weim_devtype = { 28 .cs_count = 6, 29 .cs_regs_count = 3, 30 .cs_stride = 0x10, 31 }; 32 33 static const struct imx_weim_devtype imx50_weim_devtype = { 34 .cs_count = 4, 35 .cs_regs_count = 6, 36 .cs_stride = 0x18, 37 }; 38 39 static const struct imx_weim_devtype imx51_weim_devtype = { 40 .cs_count = 6, 41 .cs_regs_count = 6, 42 .cs_stride = 0x18, 43 }; 44 45 static const struct of_device_id weim_id_table[] = { 46 /* i.MX1/21 */ 47 { .compatible = "fsl,imx1-weim", .data = &imx1_weim_devtype, }, 48 /* i.MX25/27/31/35 */ 49 { .compatible = "fsl,imx27-weim", .data = &imx27_weim_devtype, }, 50 /* i.MX50/53/6Q */ 51 { .compatible = "fsl,imx50-weim", .data = &imx50_weim_devtype, }, 52 { .compatible = "fsl,imx6q-weim", .data = &imx50_weim_devtype, }, 53 /* i.MX51 */ 54 { .compatible = "fsl,imx51-weim", .data = &imx51_weim_devtype, }, 55 { } 56 }; 57 MODULE_DEVICE_TABLE(of, weim_id_table); 58 59 /* Parse and set the timing for this device. */ 60 static int __init weim_timing_setup(struct device_node *np, void __iomem *base, 61 const struct imx_weim_devtype *devtype) 62 { 63 u32 cs_idx, value[devtype->cs_regs_count]; 64 int i, ret; 65 66 /* get the CS index from this child node's "reg" property. */ 67 ret = of_property_read_u32(np, "reg", &cs_idx); 68 if (ret) 69 return ret; 70 71 if (cs_idx >= devtype->cs_count) 72 return -EINVAL; 73 74 ret = of_property_read_u32_array(np, "fsl,weim-cs-timing", 75 value, devtype->cs_regs_count); 76 if (ret) 77 return ret; 78 79 /* set the timing for WEIM */ 80 for (i = 0; i < devtype->cs_regs_count; i++) 81 writel(value[i], base + cs_idx * devtype->cs_stride + i * 4); 82 83 return 0; 84 } 85 86 static int __init weim_parse_dt(struct platform_device *pdev, 87 void __iomem *base) 88 { 89 const struct of_device_id *of_id = of_match_device(weim_id_table, 90 &pdev->dev); 91 const struct imx_weim_devtype *devtype = of_id->data; 92 struct device_node *child; 93 int ret; 94 95 for_each_child_of_node(pdev->dev.of_node, child) { 96 if (!child->name) 97 continue; 98 99 ret = weim_timing_setup(child, base, devtype); 100 if (ret) { 101 dev_err(&pdev->dev, "%s set timing failed.\n", 102 child->full_name); 103 return ret; 104 } 105 } 106 107 ret = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev); 108 if (ret) 109 dev_err(&pdev->dev, "%s fail to create devices.\n", 110 pdev->dev.of_node->full_name); 111 return ret; 112 } 113 114 static int __init weim_probe(struct platform_device *pdev) 115 { 116 struct resource *res; 117 struct clk *clk; 118 void __iomem *base; 119 int ret; 120 121 /* get the resource */ 122 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 123 base = devm_ioremap_resource(&pdev->dev, res); 124 if (IS_ERR(base)) 125 return PTR_ERR(base); 126 127 /* get the clock */ 128 clk = devm_clk_get(&pdev->dev, NULL); 129 if (IS_ERR(clk)) 130 return PTR_ERR(clk); 131 132 ret = clk_prepare_enable(clk); 133 if (ret) 134 return ret; 135 136 /* parse the device node */ 137 ret = weim_parse_dt(pdev, base); 138 if (ret) 139 clk_disable_unprepare(clk); 140 else 141 dev_info(&pdev->dev, "Driver registered.\n"); 142 143 return ret; 144 } 145 146 static struct platform_driver weim_driver = { 147 .driver = { 148 .name = "imx-weim", 149 .owner = THIS_MODULE, 150 .of_match_table = weim_id_table, 151 }, 152 }; 153 module_platform_driver_probe(weim_driver, weim_probe); 154 155 MODULE_AUTHOR("Freescale Semiconductor Inc."); 156 MODULE_DESCRIPTION("i.MX EIM Controller Driver"); 157 MODULE_LICENSE("GPL"); 158