Commit 8bd6f53a authored by Kevin Hilman's avatar Kevin Hilman

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
parents 07031502 3f98b6ba
...@@ -8,7 +8,7 @@ The actual devices are instantiated from the child nodes of a WEIM node. ...@@ -8,7 +8,7 @@ The actual devices are instantiated from the child nodes of a WEIM node.
Required properties: Required properties:
- compatible: Should be set to "fsl,imx6q-weim" - compatible: Should be set to "fsl,<soc>-weim"
- reg: A resource specifier for the register space - reg: A resource specifier for the register space
(see the example below) (see the example below)
- clocks: the clock, see the example below. - clocks: the clock, see the example below.
...@@ -21,11 +21,18 @@ Required properties: ...@@ -21,11 +21,18 @@ Required properties:
Timing property for child nodes. It is mandatory, not optional. Timing property for child nodes. It is mandatory, not optional.
- fsl,weim-cs-timing: The timing array, contains 6 timing values for the - fsl,weim-cs-timing: The timing array, contains timing values for the
child node. We can get the CS index from the child child node. We can get the CS index from the child
node's "reg" property. This property contains the values node's "reg" property. The number of registers depends
for the registers EIM_CSnGCR1, EIM_CSnGCR2, EIM_CSnRCR1, on the selected chip.
EIM_CSnRCR2, EIM_CSnWCR1, EIM_CSnWCR2 in this order. For i.MX1, i.MX21 ("fsl,imx1-weim") there are two
registers: CSxU, CSxL.
For i.MX25, i.MX27, i.MX31 and i.MX35 ("fsl,imx27-weim")
there are three registers: CSCRxU, CSCRxL, CSCRxA.
For i.MX50, i.MX53 ("fsl,imx50-weim"),
i.MX51 ("fsl,imx51-weim") and i.MX6Q ("fsl,imx6q-weim")
there are six registers: CSxGCR1, CSxGCR2, CSxRCR1,
CSxRCR2, CSxWCR1, CSxWCR2.
Example for an imx6q-sabreauto board, the NOR flash connected to the WEIM: Example for an imx6q-sabreauto board, the NOR flash connected to the WEIM:
......
...@@ -8,10 +8,9 @@ config IMX_WEIM ...@@ -8,10 +8,9 @@ config IMX_WEIM
bool "Freescale EIM DRIVER" bool "Freescale EIM DRIVER"
depends on ARCH_MXC depends on ARCH_MXC
help help
Driver for i.MX6 WEIM controller. Driver for i.MX WEIM controller.
The WEIM(Wireless External Interface Module) works like a bus. The WEIM(Wireless External Interface Module) works like a bus.
You can attach many different devices on it, such as NOR, onenand. You can attach many different devices on it, such as NOR, onenand.
But now, we only support the Parallel NOR.
config MVEBU_MBUS config MVEBU_MBUS
bool bool
......
...@@ -12,52 +12,83 @@ ...@@ -12,52 +12,83 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/of_device.h> #include <linux/of_device.h>
struct imx_weim { struct imx_weim_devtype {
void __iomem *base; unsigned int cs_count;
struct clk *clk; unsigned int cs_regs_count;
unsigned int cs_stride;
};
static const struct imx_weim_devtype imx1_weim_devtype = {
.cs_count = 6,
.cs_regs_count = 2,
.cs_stride = 0x08,
};
static const struct imx_weim_devtype imx27_weim_devtype = {
.cs_count = 6,
.cs_regs_count = 3,
.cs_stride = 0x10,
};
static const struct imx_weim_devtype imx50_weim_devtype = {
.cs_count = 4,
.cs_regs_count = 6,
.cs_stride = 0x18,
};
static const struct imx_weim_devtype imx51_weim_devtype = {
.cs_count = 6,
.cs_regs_count = 6,
.cs_stride = 0x18,
}; };
static const struct of_device_id weim_id_table[] = { static const struct of_device_id weim_id_table[] = {
{ .compatible = "fsl,imx6q-weim", }, /* i.MX1/21 */
{} { .compatible = "fsl,imx1-weim", .data = &imx1_weim_devtype, },
/* i.MX25/27/31/35 */
{ .compatible = "fsl,imx27-weim", .data = &imx27_weim_devtype, },
/* i.MX50/53/6Q */
{ .compatible = "fsl,imx50-weim", .data = &imx50_weim_devtype, },
{ .compatible = "fsl,imx6q-weim", .data = &imx50_weim_devtype, },
/* i.MX51 */
{ .compatible = "fsl,imx51-weim", .data = &imx51_weim_devtype, },
{ }
}; };
MODULE_DEVICE_TABLE(of, weim_id_table); MODULE_DEVICE_TABLE(of, weim_id_table);
#define CS_TIMING_LEN 6
#define CS_REG_RANGE 0x18
/* Parse and set the timing for this device. */ /* Parse and set the timing for this device. */
static int static int __init weim_timing_setup(struct device_node *np, void __iomem *base,
weim_timing_setup(struct platform_device *pdev, struct device_node *np) const struct imx_weim_devtype *devtype)
{ {
struct imx_weim *weim = platform_get_drvdata(pdev); u32 cs_idx, value[devtype->cs_regs_count];
u32 value[CS_TIMING_LEN]; int i, ret;
u32 cs_idx;
int ret;
int i;
/* get the CS index from this child node's "reg" property. */ /* get the CS index from this child node's "reg" property. */
ret = of_property_read_u32(np, "reg", &cs_idx); ret = of_property_read_u32(np, "reg", &cs_idx);
if (ret) if (ret)
return ret; return ret;
/* The weim has four chip selects. */ if (cs_idx >= devtype->cs_count)
if (cs_idx > 3)
return -EINVAL; return -EINVAL;
ret = of_property_read_u32_array(np, "fsl,weim-cs-timing", ret = of_property_read_u32_array(np, "fsl,weim-cs-timing",
value, CS_TIMING_LEN); value, devtype->cs_regs_count);
if (ret) if (ret)
return ret; return ret;
/* set the timing for WEIM */ /* set the timing for WEIM */
for (i = 0; i < CS_TIMING_LEN; i++) for (i = 0; i < devtype->cs_regs_count; i++)
writel(value[i], weim->base + cs_idx * CS_REG_RANGE + i * 4); writel(value[i], base + cs_idx * devtype->cs_stride + i * 4);
return 0; return 0;
} }
static int weim_parse_dt(struct platform_device *pdev) static int __init weim_parse_dt(struct platform_device *pdev,
void __iomem *base)
{ {
const struct of_device_id *of_id = of_match_device(weim_id_table,
&pdev->dev);
const struct imx_weim_devtype *devtype = of_id->data;
struct device_node *child; struct device_node *child;
int ret; int ret;
...@@ -65,7 +96,7 @@ static int weim_parse_dt(struct platform_device *pdev) ...@@ -65,7 +96,7 @@ static int weim_parse_dt(struct platform_device *pdev)
if (!child->name) if (!child->name)
continue; continue;
ret = weim_timing_setup(pdev, child); ret = weim_timing_setup(child, base, devtype);
if (ret) { if (ret) {
dev_err(&pdev->dev, "%s set timing failed.\n", dev_err(&pdev->dev, "%s set timing failed.\n",
child->full_name); child->full_name);
...@@ -80,59 +111,47 @@ static int weim_parse_dt(struct platform_device *pdev) ...@@ -80,59 +111,47 @@ static int weim_parse_dt(struct platform_device *pdev)
return ret; return ret;
} }
static int weim_probe(struct platform_device *pdev) static int __init weim_probe(struct platform_device *pdev)
{ {
struct imx_weim *weim;
struct resource *res; struct resource *res;
int ret = -EINVAL; struct clk *clk;
void __iomem *base;
weim = devm_kzalloc(&pdev->dev, sizeof(*weim), GFP_KERNEL); int ret;
if (!weim) {
ret = -ENOMEM;
goto weim_err;
}
platform_set_drvdata(pdev, weim);
/* get the resource */ /* get the resource */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
weim->base = devm_ioremap_resource(&pdev->dev, res); base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(weim->base)) { if (IS_ERR(base))
ret = PTR_ERR(weim->base); return PTR_ERR(base);
goto weim_err;
}
/* get the clock */ /* get the clock */
weim->clk = devm_clk_get(&pdev->dev, NULL); clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(weim->clk)) if (IS_ERR(clk))
goto weim_err; return PTR_ERR(clk);
ret = clk_prepare_enable(weim->clk); ret = clk_prepare_enable(clk);
if (ret) if (ret)
goto weim_err; return ret;
/* parse the device node */ /* parse the device node */
ret = weim_parse_dt(pdev); ret = weim_parse_dt(pdev, base);
if (ret) { if (ret)
clk_disable_unprepare(weim->clk); clk_disable_unprepare(clk);
goto weim_err; else
} dev_info(&pdev->dev, "Driver registered.\n");
dev_info(&pdev->dev, "WEIM driver registered.\n");
return 0;
weim_err:
return ret; return ret;
} }
static struct platform_driver weim_driver = { static struct platform_driver weim_driver = {
.driver = { .driver = {
.name = "imx-weim", .name = "imx-weim",
.of_match_table = weim_id_table, .owner = THIS_MODULE,
.of_match_table = weim_id_table,
}, },
.probe = weim_probe,
}; };
module_platform_driver_probe(weim_driver, weim_probe);
module_platform_driver(weim_driver);
MODULE_AUTHOR("Freescale Semiconductor Inc."); MODULE_AUTHOR("Freescale Semiconductor Inc.");
MODULE_DESCRIPTION("i.MX EIM Controller Driver"); MODULE_DESCRIPTION("i.MX EIM Controller Driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment