aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHuang Shijie <b32955@freescale.com>2013-05-28 02:20:07 -0400
committerShawn Guo <shawn.guo@linaro.org>2013-06-17 04:04:28 -0400
commit85bf6d4e4b100efda8169f6f98fd65d0029c7813 (patch)
tree56c0bf6af6b3f4877af7e1b560247e7f4cb1c75c
parent81b8a3cda99076b7d8b65e63d3cc675a305f60e1 (diff)
drivers: bus: add a new driver for WEIM
The WEIM(Wireless External Interface Module) works like a bus. You can attach many different devices on it, such as NOR, onenand. In the case of i.MX6q-sabreauto, the NOR is connected to WEIM. This patch also adds the devicetree binding document. The driver only works when the devicetree is enabled. Signed-off-by: Huang Shijie <b32955@freescale.com> Acked-by: Sascha Hauer <s.hauer@pengutronix.de> Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
-rw-r--r--Documentation/devicetree/bindings/bus/imx-weim.txt49
-rw-r--r--drivers/bus/Kconfig9
-rw-r--r--drivers/bus/Makefile1
-rw-r--r--drivers/bus/imx-weim.c138
4 files changed, 197 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/bus/imx-weim.txt b/Documentation/devicetree/bindings/bus/imx-weim.txt
new file mode 100644
index 000000000000..cedc2a9c4785
--- /dev/null
+++ b/Documentation/devicetree/bindings/bus/imx-weim.txt
@@ -0,0 +1,49 @@
1Device tree bindings for i.MX Wireless External Interface Module (WEIM)
2
3The term "wireless" does not imply that the WEIM is literally an interface
4without wires. It simply means that this module was originally designed for
5wireless and mobile applications that use low-power technology.
6
7The actual devices are instantiated from the child nodes of a WEIM node.
8
9Required properties:
10
11 - compatible: Should be set to "fsl,imx6q-weim"
12 - reg: A resource specifier for the register space
13 (see the example below)
14 - clocks: the clock, see the example below.
15 - #address-cells: Must be set to 2 to allow memory address translation
16 - #size-cells: Must be set to 1 to allow CS address passing
17 - ranges: Must be set up to reflect the memory layout with four
18 integer values for each chip-select line in use:
19
20 <cs-number> 0 <physical address of mapping> <size>
21
22Timing property for child nodes. It is mandatory, not optional.
23
24 - fsl,weim-cs-timing: The timing array, contains 6 timing values for the
25 child node. We can get the CS index from the child
26 node's "reg" property. This property contains the values
27 for the registers EIM_CSnGCR1, EIM_CSnGCR2, EIM_CSnRCR1,
28 EIM_CSnRCR2, EIM_CSnWCR1, EIM_CSnWCR2 in this order.
29
30Example for an imx6q-sabreauto board, the NOR flash connected to the WEIM:
31
32 weim: weim@021b8000 {
33 compatible = "fsl,imx6q-weim";
34 reg = <0x021b8000 0x4000>;
35 clocks = <&clks 196>;
36 #address-cells = <2>;
37 #size-cells = <1>;
38 ranges = <0 0 0x08000000 0x08000000>;
39
40 nor@0,0 {
41 compatible = "cfi-flash";
42 reg = <0 0 0x02000000>;
43 #address-cells = <1>;
44 #size-cells = <1>;
45 bank-width = <2>;
46 fsl,weim-cs-timing = <0x00620081 0x00000001 0x1c022000
47 0x0000c000 0x1404a38e 0x00000000>;
48 };
49 };
diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig
index b05ecab915c4..46cd5bb098a9 100644
--- a/drivers/bus/Kconfig
+++ b/drivers/bus/Kconfig
@@ -4,6 +4,15 @@
4 4
5menu "Bus devices" 5menu "Bus devices"
6 6
7config IMX_WEIM
8 bool "Freescale EIM DRIVER"
9 depends on ARCH_MXC
10 help
11 Driver for i.MX6 WEIM controller.
12 The WEIM(Wireless External Interface Module) works like a bus.
13 You can attach many different devices on it, such as NOR, onenand.
14 But now, we only support the Parallel NOR.
15
7config MVEBU_MBUS 16config MVEBU_MBUS
8 bool 17 bool
9 depends on PLAT_ORION 18 depends on PLAT_ORION
diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile
index 3c7b53c12091..436bbccf4894 100644
--- a/drivers/bus/Makefile
+++ b/drivers/bus/Makefile
@@ -2,6 +2,7 @@
2# Makefile for the bus drivers. 2# Makefile for the bus drivers.
3# 3#
4 4
5obj-$(CONFIG_IMX_WEIM) += imx-weim.o
5obj-$(CONFIG_MVEBU_MBUS) += mvebu-mbus.o 6obj-$(CONFIG_MVEBU_MBUS) += mvebu-mbus.o
6obj-$(CONFIG_OMAP_OCP2SCP) += omap-ocp2scp.o 7obj-$(CONFIG_OMAP_OCP2SCP) += omap-ocp2scp.o
7 8
diff --git a/drivers/bus/imx-weim.c b/drivers/bus/imx-weim.c
new file mode 100644
index 000000000000..349f14e886b7
--- /dev/null
+++ b/drivers/bus/imx-weim.c
@@ -0,0 +1,138 @@
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
15struct imx_weim {
16 void __iomem *base;
17 struct clk *clk;
18};
19
20static const struct of_device_id weim_id_table[] = {
21 { .compatible = "fsl,imx6q-weim", },
22 {}
23};
24MODULE_DEVICE_TABLE(of, weim_id_table);
25
26#define CS_TIMING_LEN 6
27#define CS_REG_RANGE 0x18
28
29/* Parse and set the timing for this device. */
30static int
31weim_timing_setup(struct platform_device *pdev, struct device_node *np)
32{
33 struct imx_weim *weim = platform_get_drvdata(pdev);
34 u32 value[CS_TIMING_LEN];
35 u32 cs_idx;
36 int ret;
37 int i;
38
39 /* get the CS index from this child node's "reg" property. */
40 ret = of_property_read_u32(np, "reg", &cs_idx);
41 if (ret)
42 return ret;
43
44 /* The weim has four chip selects. */
45 if (cs_idx > 3)
46 return -EINVAL;
47
48 ret = of_property_read_u32_array(np, "fsl,weim-cs-timing",
49 value, CS_TIMING_LEN);
50 if (ret)
51 return ret;
52
53 /* set the timing for WEIM */
54 for (i = 0; i < CS_TIMING_LEN; i++)
55 writel(value[i], weim->base + cs_idx * CS_REG_RANGE + i * 4);
56 return 0;
57}
58
59static int weim_parse_dt(struct platform_device *pdev)
60{
61 struct device_node *child;
62 int ret;
63
64 for_each_child_of_node(pdev->dev.of_node, child) {
65 if (!child->name)
66 continue;
67
68 ret = weim_timing_setup(pdev, child);
69 if (ret) {
70 dev_err(&pdev->dev, "%s set timing failed.\n",
71 child->full_name);
72 return ret;
73 }
74 }
75
76 ret = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
77 if (ret)
78 dev_err(&pdev->dev, "%s fail to create devices.\n",
79 pdev->dev.of_node->full_name);
80 return ret;
81}
82
83static int weim_probe(struct platform_device *pdev)
84{
85 struct imx_weim *weim;
86 struct resource *res;
87 int ret = -EINVAL;
88
89 weim = devm_kzalloc(&pdev->dev, sizeof(*weim), GFP_KERNEL);
90 if (!weim) {
91 ret = -ENOMEM;
92 goto weim_err;
93 }
94 platform_set_drvdata(pdev, weim);
95
96 /* get the resource */
97 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
98 weim->base = devm_ioremap_resource(&pdev->dev, res);
99 if (IS_ERR(weim->base)) {
100 ret = PTR_ERR(weim->base);
101 goto weim_err;
102 }
103
104 /* get the clock */
105 weim->clk = devm_clk_get(&pdev->dev, NULL);
106 if (IS_ERR(weim->clk))
107 goto weim_err;
108
109 ret = clk_prepare_enable(weim->clk);
110 if (ret)
111 goto weim_err;
112
113 /* parse the device node */
114 ret = weim_parse_dt(pdev);
115 if (ret) {
116 clk_disable_unprepare(weim->clk);
117 goto weim_err;
118 }
119
120 dev_info(&pdev->dev, "WEIM driver registered.\n");
121 return 0;
122
123weim_err:
124 return ret;
125}
126
127static struct platform_driver weim_driver = {
128 .driver = {
129 .name = "imx-weim",
130 .of_match_table = weim_id_table,
131 },
132 .probe = weim_probe,
133};
134
135module_platform_driver(weim_driver);
136MODULE_AUTHOR("Freescale Semiconductor Inc.");
137MODULE_DESCRIPTION("i.MX EIM Controller Driver");
138MODULE_LICENSE("GPL");