xref: /openbmc/linux/drivers/memory/mvebu-devbus.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
12b72c9e3SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
23edad321SEzequiel Garcia /*
33edad321SEzequiel Garcia  * Marvell EBU SoC Device Bus Controller
43edad321SEzequiel Garcia  * (memory controller for NOR/NAND/SRAM/FPGA devices)
53edad321SEzequiel Garcia  *
6c4ec7430SThomas Petazzoni  * Copyright (C) 2013-2014 Marvell
73edad321SEzequiel Garcia  */
83edad321SEzequiel Garcia 
93edad321SEzequiel Garcia #include <linux/kernel.h>
103edad321SEzequiel Garcia #include <linux/module.h>
113edad321SEzequiel Garcia #include <linux/slab.h>
123edad321SEzequiel Garcia #include <linux/err.h>
133edad321SEzequiel Garcia #include <linux/io.h>
143edad321SEzequiel Garcia #include <linux/clk.h>
153edad321SEzequiel Garcia #include <linux/mbus.h>
163edad321SEzequiel Garcia #include <linux/of_platform.h>
173edad321SEzequiel Garcia #include <linux/of_address.h>
183edad321SEzequiel Garcia #include <linux/platform_device.h>
193edad321SEzequiel Garcia 
203edad321SEzequiel Garcia /* Register definitions */
218a33692eSThomas Petazzoni #define ARMADA_DEV_WIDTH_SHIFT		30
228a33692eSThomas Petazzoni #define ARMADA_BADR_SKEW_SHIFT		28
238a33692eSThomas Petazzoni #define ARMADA_RD_HOLD_SHIFT		23
248a33692eSThomas Petazzoni #define ARMADA_ACC_NEXT_SHIFT		17
258a33692eSThomas Petazzoni #define ARMADA_RD_SETUP_SHIFT		12
268a33692eSThomas Petazzoni #define ARMADA_ACC_FIRST_SHIFT		6
273edad321SEzequiel Garcia 
288a33692eSThomas Petazzoni #define ARMADA_SYNC_ENABLE_SHIFT	24
298a33692eSThomas Petazzoni #define ARMADA_WR_HIGH_SHIFT		16
308a33692eSThomas Petazzoni #define ARMADA_WR_LOW_SHIFT		8
313edad321SEzequiel Garcia 
3271e2e5d3SThomas Petazzoni #define ARMADA_READ_PARAM_OFFSET	0x0
3371e2e5d3SThomas Petazzoni #define ARMADA_WRITE_PARAM_OFFSET	0x4
343edad321SEzequiel Garcia 
35c4ec7430SThomas Petazzoni #define ORION_RESERVED			(0x2 << 30)
36c4ec7430SThomas Petazzoni #define ORION_BADR_SKEW_SHIFT		28
37c4ec7430SThomas Petazzoni #define ORION_WR_HIGH_EXT_BIT		BIT(27)
38c4ec7430SThomas Petazzoni #define ORION_WR_HIGH_EXT_MASK		0x8
39c4ec7430SThomas Petazzoni #define ORION_WR_LOW_EXT_BIT		BIT(26)
40c4ec7430SThomas Petazzoni #define ORION_WR_LOW_EXT_MASK		0x8
41c4ec7430SThomas Petazzoni #define ORION_ALE_WR_EXT_BIT		BIT(25)
42c4ec7430SThomas Petazzoni #define ORION_ALE_WR_EXT_MASK		0x8
43c4ec7430SThomas Petazzoni #define ORION_ACC_NEXT_EXT_BIT		BIT(24)
44c4ec7430SThomas Petazzoni #define ORION_ACC_NEXT_EXT_MASK		0x10
45c4ec7430SThomas Petazzoni #define ORION_ACC_FIRST_EXT_BIT		BIT(23)
46c4ec7430SThomas Petazzoni #define ORION_ACC_FIRST_EXT_MASK	0x10
47c4ec7430SThomas Petazzoni #define ORION_TURN_OFF_EXT_BIT		BIT(22)
48c4ec7430SThomas Petazzoni #define ORION_TURN_OFF_EXT_MASK		0x8
49c4ec7430SThomas Petazzoni #define ORION_DEV_WIDTH_SHIFT		20
50c4ec7430SThomas Petazzoni #define ORION_WR_HIGH_SHIFT		17
51c4ec7430SThomas Petazzoni #define ORION_WR_HIGH_MASK		0x7
52c4ec7430SThomas Petazzoni #define ORION_WR_LOW_SHIFT		14
53c4ec7430SThomas Petazzoni #define ORION_WR_LOW_MASK		0x7
54c4ec7430SThomas Petazzoni #define ORION_ALE_WR_SHIFT		11
55c4ec7430SThomas Petazzoni #define ORION_ALE_WR_MASK		0x7
56c4ec7430SThomas Petazzoni #define ORION_ACC_NEXT_SHIFT		7
57c4ec7430SThomas Petazzoni #define ORION_ACC_NEXT_MASK		0xF
58c4ec7430SThomas Petazzoni #define ORION_ACC_FIRST_SHIFT		3
59c4ec7430SThomas Petazzoni #define ORION_ACC_FIRST_MASK		0xF
60c4ec7430SThomas Petazzoni #define ORION_TURN_OFF_SHIFT		0
61c4ec7430SThomas Petazzoni #define ORION_TURN_OFF_MASK		0x7
62c4ec7430SThomas Petazzoni 
633edad321SEzequiel Garcia struct devbus_read_params {
643edad321SEzequiel Garcia 	u32 bus_width;
653edad321SEzequiel Garcia 	u32 badr_skew;
663edad321SEzequiel Garcia 	u32 turn_off;
673edad321SEzequiel Garcia 	u32 acc_first;
683edad321SEzequiel Garcia 	u32 acc_next;
693edad321SEzequiel Garcia 	u32 rd_setup;
703edad321SEzequiel Garcia 	u32 rd_hold;
713edad321SEzequiel Garcia };
723edad321SEzequiel Garcia 
733edad321SEzequiel Garcia struct devbus_write_params {
743edad321SEzequiel Garcia 	u32 sync_enable;
753edad321SEzequiel Garcia 	u32 wr_high;
763edad321SEzequiel Garcia 	u32 wr_low;
773edad321SEzequiel Garcia 	u32 ale_wr;
783edad321SEzequiel Garcia };
793edad321SEzequiel Garcia 
803edad321SEzequiel Garcia struct devbus {
813edad321SEzequiel Garcia 	struct device *dev;
823edad321SEzequiel Garcia 	void __iomem *base;
833edad321SEzequiel Garcia 	unsigned long tick_ps;
843edad321SEzequiel Garcia };
853edad321SEzequiel Garcia 
get_timing_param_ps(struct devbus * devbus,struct device_node * node,const char * name,u32 * ticks)863edad321SEzequiel Garcia static int get_timing_param_ps(struct devbus *devbus,
873edad321SEzequiel Garcia 			       struct device_node *node,
883edad321SEzequiel Garcia 			       const char *name,
893edad321SEzequiel Garcia 			       u32 *ticks)
903edad321SEzequiel Garcia {
913edad321SEzequiel Garcia 	u32 time_ps;
923edad321SEzequiel Garcia 	int err;
933edad321SEzequiel Garcia 
943edad321SEzequiel Garcia 	err = of_property_read_u32(node, name, &time_ps);
953edad321SEzequiel Garcia 	if (err < 0) {
96db749d17SRob Herring 		dev_err(devbus->dev, "%pOF has no '%s' property\n",
97db749d17SRob Herring 			node, name);
983edad321SEzequiel Garcia 		return err;
993edad321SEzequiel Garcia 	}
1003edad321SEzequiel Garcia 
1013edad321SEzequiel Garcia 	*ticks = (time_ps + devbus->tick_ps - 1) / devbus->tick_ps;
1023edad321SEzequiel Garcia 
1033edad321SEzequiel Garcia 	dev_dbg(devbus->dev, "%s: %u ps -> 0x%x\n",
1043edad321SEzequiel Garcia 		name, time_ps, *ticks);
1053edad321SEzequiel Garcia 	return 0;
1063edad321SEzequiel Garcia }
1073edad321SEzequiel Garcia 
devbus_get_timing_params(struct devbus * devbus,struct device_node * node,struct devbus_read_params * r,struct devbus_write_params * w)10830bd30b6SThomas Petazzoni static int devbus_get_timing_params(struct devbus *devbus,
10930bd30b6SThomas Petazzoni 				    struct device_node *node,
11030bd30b6SThomas Petazzoni 				    struct devbus_read_params *r,
11130bd30b6SThomas Petazzoni 				    struct devbus_write_params *w)
1123edad321SEzequiel Garcia {
1133edad321SEzequiel Garcia 	int err;
1143edad321SEzequiel Garcia 
11530bd30b6SThomas Petazzoni 	err = of_property_read_u32(node, "devbus,bus-width", &r->bus_width);
1163edad321SEzequiel Garcia 	if (err < 0) {
1173edad321SEzequiel Garcia 		dev_err(devbus->dev,
118db749d17SRob Herring 			"%pOF has no 'devbus,bus-width' property\n",
119db749d17SRob Herring 			node);
1203edad321SEzequiel Garcia 		return err;
1213edad321SEzequiel Garcia 	}
122ce965c3dSThomas Petazzoni 
123ce965c3dSThomas Petazzoni 	/*
124ce965c3dSThomas Petazzoni 	 * The bus width is encoded into the register as 0 for 8 bits,
125ce965c3dSThomas Petazzoni 	 * and 1 for 16 bits, so we do the necessary conversion here.
126ce965c3dSThomas Petazzoni 	 */
127bf8fba45SKrzysztof Kozlowski 	if (r->bus_width == 8) {
12830bd30b6SThomas Petazzoni 		r->bus_width = 0;
129bf8fba45SKrzysztof Kozlowski 	} else if (r->bus_width == 16) {
13030bd30b6SThomas Petazzoni 		r->bus_width = 1;
131bf8fba45SKrzysztof Kozlowski 	} else {
13230bd30b6SThomas Petazzoni 		dev_err(devbus->dev, "invalid bus width %d\n", r->bus_width);
133ce965c3dSThomas Petazzoni 		return -EINVAL;
134ce965c3dSThomas Petazzoni 	}
1353edad321SEzequiel Garcia 
1363edad321SEzequiel Garcia 	err = get_timing_param_ps(devbus, node, "devbus,badr-skew-ps",
13730bd30b6SThomas Petazzoni 				  &r->badr_skew);
1383edad321SEzequiel Garcia 	if (err < 0)
1393edad321SEzequiel Garcia 		return err;
1403edad321SEzequiel Garcia 
1413edad321SEzequiel Garcia 	err = get_timing_param_ps(devbus, node, "devbus,turn-off-ps",
14230bd30b6SThomas Petazzoni 				  &r->turn_off);
1433edad321SEzequiel Garcia 	if (err < 0)
1443edad321SEzequiel Garcia 		return err;
1453edad321SEzequiel Garcia 
1463edad321SEzequiel Garcia 	err = get_timing_param_ps(devbus, node, "devbus,acc-first-ps",
14730bd30b6SThomas Petazzoni 				  &r->acc_first);
1483edad321SEzequiel Garcia 	if (err < 0)
1493edad321SEzequiel Garcia 		return err;
1503edad321SEzequiel Garcia 
1513edad321SEzequiel Garcia 	err = get_timing_param_ps(devbus, node, "devbus,acc-next-ps",
15230bd30b6SThomas Petazzoni 				  &r->acc_next);
1533edad321SEzequiel Garcia 	if (err < 0)
1543edad321SEzequiel Garcia 		return err;
1553edad321SEzequiel Garcia 
156c4ec7430SThomas Petazzoni 	if (of_device_is_compatible(devbus->dev->of_node, "marvell,mvebu-devbus")) {
1573edad321SEzequiel Garcia 		err = get_timing_param_ps(devbus, node, "devbus,rd-setup-ps",
15830bd30b6SThomas Petazzoni 					  &r->rd_setup);
1593edad321SEzequiel Garcia 		if (err < 0)
1603edad321SEzequiel Garcia 			return err;
1613edad321SEzequiel Garcia 
1623edad321SEzequiel Garcia 		err = get_timing_param_ps(devbus, node, "devbus,rd-hold-ps",
16330bd30b6SThomas Petazzoni 					  &r->rd_hold);
1643edad321SEzequiel Garcia 		if (err < 0)
1653edad321SEzequiel Garcia 			return err;
1663edad321SEzequiel Garcia 
1673edad321SEzequiel Garcia 		err = of_property_read_u32(node, "devbus,sync-enable",
16830bd30b6SThomas Petazzoni 					   &w->sync_enable);
1693edad321SEzequiel Garcia 		if (err < 0) {
1703edad321SEzequiel Garcia 			dev_err(devbus->dev,
171db749d17SRob Herring 				"%pOF has no 'devbus,sync-enable' property\n",
172db749d17SRob Herring 				node);
1733edad321SEzequiel Garcia 			return err;
1743edad321SEzequiel Garcia 		}
175c4ec7430SThomas Petazzoni 	}
1763edad321SEzequiel Garcia 
1773edad321SEzequiel Garcia 	err = get_timing_param_ps(devbus, node, "devbus,ale-wr-ps",
17830bd30b6SThomas Petazzoni 				  &w->ale_wr);
1793edad321SEzequiel Garcia 	if (err < 0)
1803edad321SEzequiel Garcia 		return err;
1813edad321SEzequiel Garcia 
1823edad321SEzequiel Garcia 	err = get_timing_param_ps(devbus, node, "devbus,wr-low-ps",
18330bd30b6SThomas Petazzoni 				  &w->wr_low);
1843edad321SEzequiel Garcia 	if (err < 0)
1853edad321SEzequiel Garcia 		return err;
1863edad321SEzequiel Garcia 
1873edad321SEzequiel Garcia 	err = get_timing_param_ps(devbus, node, "devbus,wr-high-ps",
18830bd30b6SThomas Petazzoni 				  &w->wr_high);
1893edad321SEzequiel Garcia 	if (err < 0)
1903edad321SEzequiel Garcia 		return err;
1913edad321SEzequiel Garcia 
19230bd30b6SThomas Petazzoni 	return 0;
19330bd30b6SThomas Petazzoni }
19430bd30b6SThomas Petazzoni 
devbus_orion_set_timing_params(struct devbus * devbus,struct device_node * node,struct devbus_read_params * r,struct devbus_write_params * w)195c4ec7430SThomas Petazzoni static void devbus_orion_set_timing_params(struct devbus *devbus,
196c4ec7430SThomas Petazzoni 					  struct device_node *node,
197c4ec7430SThomas Petazzoni 					  struct devbus_read_params *r,
198c4ec7430SThomas Petazzoni 					  struct devbus_write_params *w)
199c4ec7430SThomas Petazzoni {
200c4ec7430SThomas Petazzoni 	u32 value;
201c4ec7430SThomas Petazzoni 
202c4ec7430SThomas Petazzoni 	/*
203c4ec7430SThomas Petazzoni 	 * The hardware designers found it would be a good idea to
204c4ec7430SThomas Petazzoni 	 * split most of the values in the register into two fields:
205c4ec7430SThomas Petazzoni 	 * one containing all the low-order bits, and another one
206c4ec7430SThomas Petazzoni 	 * containing just the high-order bit. For all of those
207c4ec7430SThomas Petazzoni 	 * fields, we have to split the value into these two parts.
208c4ec7430SThomas Petazzoni 	 */
209c4ec7430SThomas Petazzoni 	value =	(r->turn_off   & ORION_TURN_OFF_MASK)  << ORION_TURN_OFF_SHIFT  |
210c4ec7430SThomas Petazzoni 		(r->acc_first  & ORION_ACC_FIRST_MASK) << ORION_ACC_FIRST_SHIFT |
211c4ec7430SThomas Petazzoni 		(r->acc_next   & ORION_ACC_NEXT_MASK)  << ORION_ACC_NEXT_SHIFT  |
212c4ec7430SThomas Petazzoni 		(w->ale_wr     & ORION_ALE_WR_MASK)    << ORION_ALE_WR_SHIFT    |
213c4ec7430SThomas Petazzoni 		(w->wr_low     & ORION_WR_LOW_MASK)    << ORION_WR_LOW_SHIFT    |
214c4ec7430SThomas Petazzoni 		(w->wr_high    & ORION_WR_HIGH_MASK)   << ORION_WR_HIGH_SHIFT   |
215c4ec7430SThomas Petazzoni 		r->bus_width                           << ORION_DEV_WIDTH_SHIFT |
216c4ec7430SThomas Petazzoni 		((r->turn_off  & ORION_TURN_OFF_EXT_MASK)  ? ORION_TURN_OFF_EXT_BIT  : 0) |
217c4ec7430SThomas Petazzoni 		((r->acc_first & ORION_ACC_FIRST_EXT_MASK) ? ORION_ACC_FIRST_EXT_BIT : 0) |
218c4ec7430SThomas Petazzoni 		((r->acc_next  & ORION_ACC_NEXT_EXT_MASK)  ? ORION_ACC_NEXT_EXT_BIT  : 0) |
219c4ec7430SThomas Petazzoni 		((w->ale_wr    & ORION_ALE_WR_EXT_MASK)    ? ORION_ALE_WR_EXT_BIT    : 0) |
220c4ec7430SThomas Petazzoni 		((w->wr_low    & ORION_WR_LOW_EXT_MASK)    ? ORION_WR_LOW_EXT_BIT    : 0) |
221c4ec7430SThomas Petazzoni 		((w->wr_high   & ORION_WR_HIGH_EXT_MASK)   ? ORION_WR_HIGH_EXT_BIT   : 0) |
222c4ec7430SThomas Petazzoni 		(r->badr_skew << ORION_BADR_SKEW_SHIFT) |
223c4ec7430SThomas Petazzoni 		ORION_RESERVED;
224c4ec7430SThomas Petazzoni 
225c4ec7430SThomas Petazzoni 	writel(value, devbus->base);
226c4ec7430SThomas Petazzoni }
227c4ec7430SThomas Petazzoni 
devbus_armada_set_timing_params(struct devbus * devbus,struct device_node * node,struct devbus_read_params * r,struct devbus_write_params * w)22830bd30b6SThomas Petazzoni static void devbus_armada_set_timing_params(struct devbus *devbus,
22930bd30b6SThomas Petazzoni 					   struct device_node *node,
23030bd30b6SThomas Petazzoni 					   struct devbus_read_params *r,
23130bd30b6SThomas Petazzoni 					   struct devbus_write_params *w)
23230bd30b6SThomas Petazzoni {
23330bd30b6SThomas Petazzoni 	u32 value;
23430bd30b6SThomas Petazzoni 
2353edad321SEzequiel Garcia 	/* Set read timings */
23630bd30b6SThomas Petazzoni 	value = r->bus_width << ARMADA_DEV_WIDTH_SHIFT |
23730bd30b6SThomas Petazzoni 		r->badr_skew << ARMADA_BADR_SKEW_SHIFT |
23830bd30b6SThomas Petazzoni 		r->rd_hold   << ARMADA_RD_HOLD_SHIFT   |
23930bd30b6SThomas Petazzoni 		r->acc_next  << ARMADA_ACC_NEXT_SHIFT  |
24030bd30b6SThomas Petazzoni 		r->rd_setup  << ARMADA_RD_SETUP_SHIFT  |
24130bd30b6SThomas Petazzoni 		r->acc_first << ARMADA_ACC_FIRST_SHIFT |
24230bd30b6SThomas Petazzoni 		r->turn_off;
2433edad321SEzequiel Garcia 
2443edad321SEzequiel Garcia 	dev_dbg(devbus->dev, "read parameters register 0x%p = 0x%x\n",
24571e2e5d3SThomas Petazzoni 		devbus->base + ARMADA_READ_PARAM_OFFSET,
2463edad321SEzequiel Garcia 		value);
2473edad321SEzequiel Garcia 
24871e2e5d3SThomas Petazzoni 	writel(value, devbus->base + ARMADA_READ_PARAM_OFFSET);
2493edad321SEzequiel Garcia 
2503edad321SEzequiel Garcia 	/* Set write timings */
25130bd30b6SThomas Petazzoni 	value = w->sync_enable  << ARMADA_SYNC_ENABLE_SHIFT |
25230bd30b6SThomas Petazzoni 		w->wr_low       << ARMADA_WR_LOW_SHIFT      |
25330bd30b6SThomas Petazzoni 		w->wr_high      << ARMADA_WR_HIGH_SHIFT     |
25430bd30b6SThomas Petazzoni 		w->ale_wr;
2553edad321SEzequiel Garcia 
2563edad321SEzequiel Garcia 	dev_dbg(devbus->dev, "write parameters register: 0x%p = 0x%x\n",
25771e2e5d3SThomas Petazzoni 		devbus->base + ARMADA_WRITE_PARAM_OFFSET,
2583edad321SEzequiel Garcia 		value);
2593edad321SEzequiel Garcia 
26071e2e5d3SThomas Petazzoni 	writel(value, devbus->base + ARMADA_WRITE_PARAM_OFFSET);
2613edad321SEzequiel Garcia }
2623edad321SEzequiel Garcia 
mvebu_devbus_probe(struct platform_device * pdev)2633edad321SEzequiel Garcia static int mvebu_devbus_probe(struct platform_device *pdev)
2643edad321SEzequiel Garcia {
2653edad321SEzequiel Garcia 	struct device *dev = &pdev->dev;
2663edad321SEzequiel Garcia 	struct device_node *node = pdev->dev.of_node;
26730bd30b6SThomas Petazzoni 	struct devbus_read_params r;
26830bd30b6SThomas Petazzoni 	struct devbus_write_params w;
2693edad321SEzequiel Garcia 	struct devbus *devbus;
2703edad321SEzequiel Garcia 	struct clk *clk;
2713edad321SEzequiel Garcia 	unsigned long rate;
2729b6e4c0aSEzequiel Garcia 	int err;
2733edad321SEzequiel Garcia 
2743edad321SEzequiel Garcia 	devbus = devm_kzalloc(&pdev->dev, sizeof(struct devbus), GFP_KERNEL);
2753edad321SEzequiel Garcia 	if (!devbus)
2763edad321SEzequiel Garcia 		return -ENOMEM;
2773edad321SEzequiel Garcia 
2783edad321SEzequiel Garcia 	devbus->dev = dev;
279f3ba1c86SYangtao Li 	devbus->base = devm_platform_ioremap_resource(pdev, 0);
2803edad321SEzequiel Garcia 	if (IS_ERR(devbus->base))
2813edad321SEzequiel Garcia 		return PTR_ERR(devbus->base);
2823edad321SEzequiel Garcia 
283*cb8fd6f7SGaosheng Cui 	clk = devm_clk_get_enabled(&pdev->dev, NULL);
2843edad321SEzequiel Garcia 	if (IS_ERR(clk))
2853edad321SEzequiel Garcia 		return PTR_ERR(clk);
2863edad321SEzequiel Garcia 
2873edad321SEzequiel Garcia 	/*
2883edad321SEzequiel Garcia 	 * Obtain clock period in picoseconds,
2893edad321SEzequiel Garcia 	 * we need this in order to convert timing
2903edad321SEzequiel Garcia 	 * parameters from cycles to picoseconds.
2913edad321SEzequiel Garcia 	 */
2923edad321SEzequiel Garcia 	rate = clk_get_rate(clk) / 1000;
2933edad321SEzequiel Garcia 	devbus->tick_ps = 1000000000 / rate;
2943edad321SEzequiel Garcia 
29530bd30b6SThomas Petazzoni 	dev_dbg(devbus->dev, "Setting timing parameter, tick is %lu ps\n",
29630bd30b6SThomas Petazzoni 		devbus->tick_ps);
29730bd30b6SThomas Petazzoni 
2980456d330SThomas Petazzoni 	if (!of_property_read_bool(node, "devbus,keep-config")) {
29930bd30b6SThomas Petazzoni 		/* Read the Device Tree node */
30030bd30b6SThomas Petazzoni 		err = devbus_get_timing_params(devbus, node, &r, &w);
3013edad321SEzequiel Garcia 		if (err < 0)
3023edad321SEzequiel Garcia 			return err;
3033edad321SEzequiel Garcia 
30430bd30b6SThomas Petazzoni 		/* Set the new timing parameters */
305c4ec7430SThomas Petazzoni 		if (of_device_is_compatible(node, "marvell,orion-devbus"))
306c4ec7430SThomas Petazzoni 			devbus_orion_set_timing_params(devbus, node, &r, &w);
307c4ec7430SThomas Petazzoni 		else
30830bd30b6SThomas Petazzoni 			devbus_armada_set_timing_params(devbus, node, &r, &w);
3090456d330SThomas Petazzoni 	}
31030bd30b6SThomas Petazzoni 
3113edad321SEzequiel Garcia 	/*
3123edad321SEzequiel Garcia 	 * We need to create a child device explicitly from here to
3133edad321SEzequiel Garcia 	 * guarantee that the child will be probed after the timing
3143edad321SEzequiel Garcia 	 * parameters for the bus are written.
3153edad321SEzequiel Garcia 	 */
3163edad321SEzequiel Garcia 	err = of_platform_populate(node, NULL, NULL, dev);
3179b6e4c0aSEzequiel Garcia 	if (err < 0)
3183edad321SEzequiel Garcia 		return err;
3193edad321SEzequiel Garcia 
3203edad321SEzequiel Garcia 	return 0;
3213edad321SEzequiel Garcia }
3223edad321SEzequiel Garcia 
3233edad321SEzequiel Garcia static const struct of_device_id mvebu_devbus_of_match[] = {
3243edad321SEzequiel Garcia 	{ .compatible = "marvell,mvebu-devbus" },
325c4ec7430SThomas Petazzoni 	{ .compatible = "marvell,orion-devbus" },
3263edad321SEzequiel Garcia 	{},
3273edad321SEzequiel Garcia };
3283edad321SEzequiel Garcia MODULE_DEVICE_TABLE(of, mvebu_devbus_of_match);
3293edad321SEzequiel Garcia 
3303edad321SEzequiel Garcia static struct platform_driver mvebu_devbus_driver = {
3313edad321SEzequiel Garcia 	.probe		= mvebu_devbus_probe,
3323edad321SEzequiel Garcia 	.driver		= {
3333edad321SEzequiel Garcia 		.name	= "mvebu-devbus",
3343edad321SEzequiel Garcia 		.of_match_table = mvebu_devbus_of_match,
3353edad321SEzequiel Garcia 	},
3363edad321SEzequiel Garcia };
3373edad321SEzequiel Garcia 
mvebu_devbus_init(void)3383edad321SEzequiel Garcia static int __init mvebu_devbus_init(void)
3393edad321SEzequiel Garcia {
3403edad321SEzequiel Garcia 	return platform_driver_register(&mvebu_devbus_driver);
3413edad321SEzequiel Garcia }
3423edad321SEzequiel Garcia module_init(mvebu_devbus_init);
3433edad321SEzequiel Garcia 
3443edad321SEzequiel Garcia MODULE_AUTHOR("Ezequiel Garcia <ezequiel.garcia@free-electrons.com>");
3453edad321SEzequiel Garcia MODULE_DESCRIPTION("Marvell EBU SoC Device Bus controller");
346