summaryrefslogtreecommitdiffstats
path: root/drivers/bus/imx-weim.c
blob: c62e948f5b7d917f3e12b8f4810ba7dc10d0fc29 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
/*
 * EIM driver for Freescale's i.MX chips
 *
 * Copyright (C) 2013 Freescale Semiconductor, Inc.
 *
 * This file is licensed under the terms of the GNU General Public
 * License version 2. This program is licensed "as is" without any
 * warranty of any kind, whether express or implied.
 */
#include <common.h>
#include <driver.h>
#include <init.h>
#include <io.h>
#include <of.h>
#include <linux/err.h>

struct imx_weim_devtype {
	unsigned int	cs_count;
	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 struct of_device_id weim_id_table[] = {
	{
		/* 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,
	}, {
		/* i.MX51 */
		.compatible = "fsl,imx51-weim",
		.data = &imx51_weim_devtype,
	}, {
		.compatible = "fsl,imx6q-weim",
		.data = &imx50_weim_devtype,
	}, {
	}
};

struct imx_weim {
	struct device_d *dev;
	void __iomem *base;
	struct imx_weim_devtype *devtype;
};

/* Parse and set the timing for this device. */
static int
weim_timing_setup(struct imx_weim *weim, struct device_node *np)
{
	struct imx_weim_devtype *devtype = weim->devtype;
	u32 cs_idx, value[devtype->cs_regs_count];
	int i, ret;

	/* get the CS index from this child node's "reg" property. */
	ret = of_property_read_u32(np, "reg", &cs_idx);
	if (ret)
		return ret;

	if (cs_idx >= devtype->cs_count)
		return -EINVAL;

	ret = of_property_read_u32_array(np, "fsl,weim-cs-timing",
			value, devtype->cs_regs_count);
	if (ret)
		return ret;

	dev_dbg(weim->dev, "setting up cs for %s\n", np->name);

	/* set the timing for WEIM */
	for (i = 0; i < devtype->cs_regs_count; i++)
		writel(value[i], weim->base + cs_idx * devtype->cs_stride + i * 4);

	return 0;
}

static int weim_parse_dt(struct imx_weim *weim)
{
	struct device_node *child;
	int ret;

	for_each_child_of_node(weim->dev->device_node, child) {
		if (!child->name)
			continue;

		ret = weim_timing_setup(weim, child);
		if (ret) {
			dev_err(weim->dev, "%s set timing failed.\n",
				child->full_name);
			return ret;
		}
	}

	ret = of_platform_populate(weim->dev->device_node, NULL, weim->dev);
	if (ret)
		dev_err(weim->dev, "%s fail to create devices.\n",
			weim->dev->device_node->full_name);
	return ret;
}

static int weim_probe(struct device_d *dev)
{
	struct resource *iores;
	struct imx_weim_devtype *devtype;
	struct imx_weim *weim;
	int ret;

	ret = dev_get_drvdata(dev, (const void **)&devtype);
	if (ret)
		return ret;

	weim = xzalloc(sizeof(*weim));

	weim->dev = dev;
	weim->devtype = devtype;

	/* get the resource */
	iores = dev_request_mem_resource(dev, 0);
	if (IS_ERR(iores)) {
		ret = PTR_ERR(iores);
		goto weim_err;
	}
	weim->base = IOMEM(iores->start);

	/* parse the device node */
	ret = weim_parse_dt(weim);
	if (ret) {
		goto weim_err;
	}

	dev_info(dev, "WEIM driver registered.\n");

	return 0;

weim_err:
	return ret;
}

static struct driver_d weim_driver = {
	.name = "imx-weim",
	.of_compatible = DRV_OF_COMPAT(weim_id_table),
	.probe   = weim_probe,
};
device_platform_driver(weim_driver);