Commit 8bd6f53af54b7dbf13625479ae673e73f61ff46a
Exists in
smarc-imx_3.14.28_1.0.0_ga
and in
1 other branch
Merge tag 'imx-weim-3.12' of git://git.linaro.org/people/shawnguo/linux-2.6 into next/soc
From Shawn Guo: This is a patch series that updates imx-weim bus driver to have it support more i.MX SoCs. Because there is no maintainer for drivers/bus so far, I'm forwarding it through IMX tree for 3.12 merge window. * tag 'imx-weim-3.12' of git://git.linaro.org/people/shawnguo/linux-2.6: drivers: bus: imx-weim: Add support for i.MX1/21/25/27/31/35/50/51/53 drivers: bus: imx-weim: Add missing platform_driver.owner field drivers: bus: imx-weim: use module_platform_driver_probe() drivers: bus: imx-weim: Simplify error path drivers: bus: imx-weim: Remove private driver data
Showing 3 changed files Side-by-side Diff
Documentation/devicetree/bindings/bus/imx-weim.txt
... | ... | @@ -8,7 +8,7 @@ |
8 | 8 | |
9 | 9 | Required properties: |
10 | 10 | |
11 | - - compatible: Should be set to "fsl,imx6q-weim" | |
11 | + - compatible: Should be set to "fsl,<soc>-weim" | |
12 | 12 | - reg: A resource specifier for the register space |
13 | 13 | (see the example below) |
14 | 14 | - clocks: the clock, see the example below. |
15 | 15 | |
... | ... | @@ -21,11 +21,18 @@ |
21 | 21 | |
22 | 22 | Timing property for child nodes. It is mandatory, not optional. |
23 | 23 | |
24 | - - fsl,weim-cs-timing: The timing array, contains 6 timing values for the | |
24 | + - fsl,weim-cs-timing: The timing array, contains timing values for the | |
25 | 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. | |
26 | + node's "reg" property. The number of registers depends | |
27 | + on the selected chip. | |
28 | + For i.MX1, i.MX21 ("fsl,imx1-weim") there are two | |
29 | + registers: CSxU, CSxL. | |
30 | + For i.MX25, i.MX27, i.MX31 and i.MX35 ("fsl,imx27-weim") | |
31 | + there are three registers: CSCRxU, CSCRxL, CSCRxA. | |
32 | + For i.MX50, i.MX53 ("fsl,imx50-weim"), | |
33 | + i.MX51 ("fsl,imx51-weim") and i.MX6Q ("fsl,imx6q-weim") | |
34 | + there are six registers: CSxGCR1, CSxGCR2, CSxRCR1, | |
35 | + CSxRCR2, CSxWCR1, CSxWCR2. | |
29 | 36 | |
30 | 37 | Example for an imx6q-sabreauto board, the NOR flash connected to the WEIM: |
31 | 38 |
drivers/bus/Kconfig
... | ... | @@ -8,10 +8,9 @@ |
8 | 8 | bool "Freescale EIM DRIVER" |
9 | 9 | depends on ARCH_MXC |
10 | 10 | help |
11 | - Driver for i.MX6 WEIM controller. | |
11 | + Driver for i.MX WEIM controller. | |
12 | 12 | The WEIM(Wireless External Interface Module) works like a bus. |
13 | 13 | You can attach many different devices on it, such as NOR, onenand. |
14 | - But now, we only support the Parallel NOR. | |
15 | 14 | |
16 | 15 | config MVEBU_MBUS |
17 | 16 | bool |
drivers/bus/imx-weim.c
... | ... | @@ -12,52 +12,83 @@ |
12 | 12 | #include <linux/io.h> |
13 | 13 | #include <linux/of_device.h> |
14 | 14 | |
15 | -struct imx_weim { | |
16 | - void __iomem *base; | |
17 | - struct clk *clk; | |
15 | +struct imx_weim_devtype { | |
16 | + unsigned int cs_count; | |
17 | + unsigned int cs_regs_count; | |
18 | + unsigned int cs_stride; | |
18 | 19 | }; |
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 | + | |
20 | 45 | static const struct of_device_id weim_id_table[] = { |
21 | - { .compatible = "fsl,imx6q-weim", }, | |
22 | - {} | |
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 | + { } | |
23 | 56 | }; |
24 | 57 | MODULE_DEVICE_TABLE(of, weim_id_table); |
25 | 58 | |
26 | -#define CS_TIMING_LEN 6 | |
27 | -#define CS_REG_RANGE 0x18 | |
28 | - | |
29 | 59 | /* Parse and set the timing for this device. */ |
30 | -static int | |
31 | -weim_timing_setup(struct platform_device *pdev, struct device_node *np) | |
60 | +static int __init weim_timing_setup(struct device_node *np, void __iomem *base, | |
61 | + const struct imx_weim_devtype *devtype) | |
32 | 62 | { |
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; | |
63 | + u32 cs_idx, value[devtype->cs_regs_count]; | |
64 | + int i, ret; | |
38 | 65 | |
39 | 66 | /* get the CS index from this child node's "reg" property. */ |
40 | 67 | ret = of_property_read_u32(np, "reg", &cs_idx); |
41 | 68 | if (ret) |
42 | 69 | return ret; |
43 | 70 | |
44 | - /* The weim has four chip selects. */ | |
45 | - if (cs_idx > 3) | |
71 | + if (cs_idx >= devtype->cs_count) | |
46 | 72 | return -EINVAL; |
47 | 73 | |
48 | 74 | ret = of_property_read_u32_array(np, "fsl,weim-cs-timing", |
49 | - value, CS_TIMING_LEN); | |
75 | + value, devtype->cs_regs_count); | |
50 | 76 | if (ret) |
51 | 77 | return ret; |
52 | 78 | |
53 | 79 | /* 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); | |
80 | + for (i = 0; i < devtype->cs_regs_count; i++) | |
81 | + writel(value[i], base + cs_idx * devtype->cs_stride + i * 4); | |
82 | + | |
56 | 83 | return 0; |
57 | 84 | } |
58 | 85 | |
59 | -static int weim_parse_dt(struct platform_device *pdev) | |
86 | +static int __init weim_parse_dt(struct platform_device *pdev, | |
87 | + void __iomem *base) | |
60 | 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; | |
61 | 92 | struct device_node *child; |
62 | 93 | int ret; |
63 | 94 | |
... | ... | @@ -65,7 +96,7 @@ |
65 | 96 | if (!child->name) |
66 | 97 | continue; |
67 | 98 | |
68 | - ret = weim_timing_setup(pdev, child); | |
99 | + ret = weim_timing_setup(child, base, devtype); | |
69 | 100 | if (ret) { |
70 | 101 | dev_err(&pdev->dev, "%s set timing failed.\n", |
71 | 102 | child->full_name); |
72 | 103 | |
73 | 104 | |
74 | 105 | |
75 | 106 | |
76 | 107 | |
77 | 108 | |
78 | 109 | |
79 | 110 | |
80 | 111 | |
81 | 112 | |
82 | 113 | |
83 | 114 | |
84 | 115 | |
... | ... | @@ -80,59 +111,47 @@ |
80 | 111 | return ret; |
81 | 112 | } |
82 | 113 | |
83 | -static int weim_probe(struct platform_device *pdev) | |
114 | +static int __init weim_probe(struct platform_device *pdev) | |
84 | 115 | { |
85 | - struct imx_weim *weim; | |
86 | 116 | struct resource *res; |
87 | - int ret = -EINVAL; | |
117 | + struct clk *clk; | |
118 | + void __iomem *base; | |
119 | + int ret; | |
88 | 120 | |
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 | 121 | /* get the resource */ |
97 | 122 | 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 | - } | |
123 | + base = devm_ioremap_resource(&pdev->dev, res); | |
124 | + if (IS_ERR(base)) | |
125 | + return PTR_ERR(base); | |
103 | 126 | |
104 | 127 | /* get the clock */ |
105 | - weim->clk = devm_clk_get(&pdev->dev, NULL); | |
106 | - if (IS_ERR(weim->clk)) | |
107 | - goto weim_err; | |
128 | + clk = devm_clk_get(&pdev->dev, NULL); | |
129 | + if (IS_ERR(clk)) | |
130 | + return PTR_ERR(clk); | |
108 | 131 | |
109 | - ret = clk_prepare_enable(weim->clk); | |
132 | + ret = clk_prepare_enable(clk); | |
110 | 133 | if (ret) |
111 | - goto weim_err; | |
134 | + return ret; | |
112 | 135 | |
113 | 136 | /* parse the device node */ |
114 | - ret = weim_parse_dt(pdev); | |
115 | - if (ret) { | |
116 | - clk_disable_unprepare(weim->clk); | |
117 | - goto weim_err; | |
118 | - } | |
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"); | |
119 | 142 | |
120 | - dev_info(&pdev->dev, "WEIM driver registered.\n"); | |
121 | - return 0; | |
122 | - | |
123 | -weim_err: | |
124 | 143 | return ret; |
125 | 144 | } |
126 | 145 | |
127 | 146 | static struct platform_driver weim_driver = { |
128 | 147 | .driver = { |
129 | - .name = "imx-weim", | |
130 | - .of_match_table = weim_id_table, | |
148 | + .name = "imx-weim", | |
149 | + .owner = THIS_MODULE, | |
150 | + .of_match_table = weim_id_table, | |
131 | 151 | }, |
132 | - .probe = weim_probe, | |
133 | 152 | }; |
153 | +module_platform_driver_probe(weim_driver, weim_probe); | |
134 | 154 | |
135 | -module_platform_driver(weim_driver); | |
136 | 155 | MODULE_AUTHOR("Freescale Semiconductor Inc."); |
137 | 156 | MODULE_DESCRIPTION("i.MX EIM Controller Driver"); |
138 | 157 | MODULE_LICENSE("GPL"); |