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 static const struct of_device_id weim_id_table[] = { 16 { .compatible = "fsl,imx6q-weim", }, 17 {} 18 }; 19 MODULE_DEVICE_TABLE(of, weim_id_table); 20 21 #define CS_TIMING_LEN 6 22 #define CS_REG_RANGE 0x18 23 24 /* Parse and set the timing for this device. */ 25 static int weim_timing_setup(struct device_node *np, void __iomem *base) 26 { 27 u32 value[CS_TIMING_LEN]; 28 u32 cs_idx; 29 int ret; 30 int i; 31 32 /* get the CS index from this child node's "reg" property. */ 33 ret = of_property_read_u32(np, "reg", &cs_idx); 34 if (ret) 35 return ret; 36 37 /* The weim has four chip selects. */ 38 if (cs_idx > 3) 39 return -EINVAL; 40 41 ret = of_property_read_u32_array(np, "fsl,weim-cs-timing", 42 value, CS_TIMING_LEN); 43 if (ret) 44 return ret; 45 46 /* set the timing for WEIM */ 47 for (i = 0; i < CS_TIMING_LEN; i++) 48 writel(value[i], base + cs_idx * CS_REG_RANGE + i * 4); 49 return 0; 50 } 51 52 static int weim_parse_dt(struct platform_device *pdev, void __iomem *base) 53 { 54 struct device_node *child; 55 int ret; 56 57 for_each_child_of_node(pdev->dev.of_node, child) { 58 if (!child->name) 59 continue; 60 61 ret = weim_timing_setup(child, base); 62 if (ret) { 63 dev_err(&pdev->dev, "%s set timing failed.\n", 64 child->full_name); 65 return ret; 66 } 67 } 68 69 ret = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev); 70 if (ret) 71 dev_err(&pdev->dev, "%s fail to create devices.\n", 72 pdev->dev.of_node->full_name); 73 return ret; 74 } 75 76 static int weim_probe(struct platform_device *pdev) 77 { 78 struct resource *res; 79 struct clk *clk; 80 void __iomem *base; 81 int ret; 82 83 /* get the resource */ 84 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 85 base = devm_ioremap_resource(&pdev->dev, res); 86 if (IS_ERR(base)) 87 return PTR_ERR(base); 88 89 /* get the clock */ 90 clk = devm_clk_get(&pdev->dev, NULL); 91 if (IS_ERR(clk)) 92 return PTR_ERR(clk); 93 94 ret = clk_prepare_enable(clk); 95 if (ret) 96 return ret; 97 98 /* parse the device node */ 99 ret = weim_parse_dt(pdev, base); 100 if (ret) 101 clk_disable_unprepare(clk); 102 else 103 dev_info(&pdev->dev, "Driver registered.\n"); 104 105 return ret; 106 } 107 108 static struct platform_driver weim_driver = { 109 .driver = { 110 .name = "imx-weim", 111 .of_match_table = weim_id_table, 112 }, 113 .probe = weim_probe, 114 }; 115 116 module_platform_driver(weim_driver); 117 MODULE_AUTHOR("Freescale Semiconductor Inc."); 118 MODULE_DESCRIPTION("i.MX EIM Controller Driver"); 119 MODULE_LICENSE("GPL"); 120