diff options
Diffstat (limited to 'drivers/mfd/vexpress-sysreg.c')
| -rw-r--r-- | drivers/mfd/vexpress-sysreg.c | 554 | 
1 files changed, 151 insertions, 403 deletions
diff --git a/drivers/mfd/vexpress-sysreg.c b/drivers/mfd/vexpress-sysreg.c index 981bef4b7eb..9e21e4fc959 100644 --- a/drivers/mfd/vexpress-sysreg.c +++ b/drivers/mfd/vexpress-sysreg.c @@ -11,23 +11,22 @@   * Copyright (C) 2012 ARM Limited   */ +#include <linux/basic_mmio_gpio.h>  #include <linux/err.h> -#include <linux/gpio.h>  #include <linux/io.h> -#include <linux/leds.h> +#include <linux/mfd/core.h>  #include <linux/of_address.h> +#include <linux/of_platform.h> +#include <linux/platform_data/syscon.h>  #include <linux/platform_device.h> -#include <linux/regulator/driver.h>  #include <linux/slab.h>  #include <linux/stat.h> -#include <linux/timer.h>  #include <linux/vexpress.h>  #define SYS_ID			0x000  #define SYS_SW			0x004  #define SYS_LED			0x008  #define SYS_100HZ		0x024 -#define SYS_FLAGS		0x030  #define SYS_FLAGSSET		0x030  #define SYS_FLAGSCLR		0x034  #define SYS_NVFLAGS		0x038 @@ -46,465 +45,209 @@  #define SYS_CFGSTAT		0x0a8  #define SYS_HBI_MASK		0xfff -#define SYS_ID_HBI_SHIFT	16  #define SYS_PROCIDx_HBI_SHIFT	0 -#define SYS_LED_LED(n)		(1 << (n)) -  #define SYS_MCI_CARDIN		(1 << 0)  #define SYS_MCI_WPROT		(1 << 1) -#define SYS_FLASH_WPn		(1 << 0) -  #define SYS_MISC_MASTERSITE	(1 << 14) -#define SYS_CFGCTRL_START	(1 << 31) -#define SYS_CFGCTRL_WRITE	(1 << 30) -#define SYS_CFGCTRL_DCC(n)	(((n) & 0xf) << 26) -#define SYS_CFGCTRL_FUNC(n)	(((n) & 0x3f) << 20) -#define SYS_CFGCTRL_SITE(n)	(((n) & 0x3) << 16) -#define SYS_CFGCTRL_POSITION(n)	(((n) & 0xf) << 12) -#define SYS_CFGCTRL_DEVICE(n)	(((n) & 0xfff) << 0) - -#define SYS_CFGSTAT_ERR		(1 << 1) -#define SYS_CFGSTAT_COMPLETE	(1 << 0) - - -static void __iomem *vexpress_sysreg_base; -static struct device *vexpress_sysreg_dev; -static int vexpress_master_site; - -void vexpress_flags_set(u32 data) -{ -	writel(~0, vexpress_sysreg_base + SYS_FLAGSCLR); -	writel(data, vexpress_sysreg_base + SYS_FLAGSSET); -} +static void __iomem *__vexpress_sysreg_base; -u32 vexpress_get_procid(int site) +static void __iomem *vexpress_sysreg_base(void)  { -	if (site == VEXPRESS_SITE_MASTER) -		site = vexpress_master_site; - -	return readl(vexpress_sysreg_base + (site == VEXPRESS_SITE_DB1 ? -			SYS_PROCID0 : SYS_PROCID1)); -} +	if (!__vexpress_sysreg_base) { +		struct device_node *node = of_find_compatible_node(NULL, NULL, +				"arm,vexpress-sysreg"); -u32 vexpress_get_hbi(int site) -{ -	u32 id; - -	switch (site) { -	case VEXPRESS_SITE_MB: -		id = readl(vexpress_sysreg_base + SYS_ID); -		return (id >> SYS_ID_HBI_SHIFT) & SYS_HBI_MASK; -	case VEXPRESS_SITE_MASTER: -	case VEXPRESS_SITE_DB1: -	case VEXPRESS_SITE_DB2: -		id = vexpress_get_procid(site); -		return (id >> SYS_PROCIDx_HBI_SHIFT) & SYS_HBI_MASK; +		__vexpress_sysreg_base = of_iomap(node, 0);  	} -	return ~0; -} +	WARN_ON(!__vexpress_sysreg_base); -void __iomem *vexpress_get_24mhz_clock_base(void) -{ -	return vexpress_sysreg_base + SYS_24MHZ; +	return __vexpress_sysreg_base;  } -static void vexpress_sysreg_find_prop(struct device_node *node, -		const char *name, u32 *val) +static int vexpress_sysreg_get_master(void)  { -	of_node_get(node); -	while (node) { -		if (of_property_read_u32(node, name, val) == 0) { -			of_node_put(node); -			return; -		} -		node = of_get_next_parent(node); -	} -} - -unsigned __vexpress_get_site(struct device *dev, struct device_node *node) -{ -	u32 site = 0; - -	WARN_ON(dev && node && dev->of_node != node); -	if (dev && !node) -		node = dev->of_node; - -	if (node) { -		vexpress_sysreg_find_prop(node, "arm,vexpress,site", &site); -	} else if (dev && dev->bus == &platform_bus_type) { -		struct platform_device *pdev = to_platform_device(dev); - -		if (pdev->num_resources == 1 && -				pdev->resource[0].flags == IORESOURCE_BUS) -			site = pdev->resource[0].start; -	} else if (dev && strncmp(dev_name(dev), "ct:", 3) == 0) { -		site = VEXPRESS_SITE_MASTER; -	} +	if (readl(vexpress_sysreg_base() + SYS_MISC) & SYS_MISC_MASTERSITE) +		return VEXPRESS_SITE_DB2; -	if (site == VEXPRESS_SITE_MASTER) -		site = vexpress_master_site; - -	return site; +	return VEXPRESS_SITE_DB1;  } - -struct vexpress_sysreg_config_func { -	u32 template; -	u32 device; -}; - -static struct vexpress_config_bridge *vexpress_sysreg_config_bridge; -static struct timer_list vexpress_sysreg_config_timer; -static u32 *vexpress_sysreg_config_data; -static int vexpress_sysreg_config_tries; - -static void *vexpress_sysreg_config_func_get(struct device *dev, -		struct device_node *node) +void vexpress_flags_set(u32 data)  { -	struct vexpress_sysreg_config_func *config_func; -	u32 site; -	u32 position = 0; -	u32 dcc = 0; -	u32 func_device[2]; -	int err = -EFAULT; - -	if (node) { -		of_node_get(node); -		vexpress_sysreg_find_prop(node, "arm,vexpress,site", &site); -		vexpress_sysreg_find_prop(node, "arm,vexpress,position", -				&position); -		vexpress_sysreg_find_prop(node, "arm,vexpress,dcc", &dcc); -		err = of_property_read_u32_array(node, -				"arm,vexpress-sysreg,func", func_device, -				ARRAY_SIZE(func_device)); -		of_node_put(node); -	} else if (dev && dev->bus == &platform_bus_type) { -		struct platform_device *pdev = to_platform_device(dev); - -		if (pdev->num_resources == 1 && -				pdev->resource[0].flags == IORESOURCE_BUS) { -			site = pdev->resource[0].start; -			func_device[0] = pdev->resource[0].end; -			func_device[1] = pdev->id; -			err = 0; -		} -	} -	if (err) -		return NULL; - -	config_func = kzalloc(sizeof(*config_func), GFP_KERNEL); -	if (!config_func) -		return NULL; - -	config_func->template = SYS_CFGCTRL_DCC(dcc); -	config_func->template |= SYS_CFGCTRL_FUNC(func_device[0]); -	config_func->template |= SYS_CFGCTRL_SITE(site == VEXPRESS_SITE_MASTER ? -			vexpress_master_site : site); -	config_func->template |= SYS_CFGCTRL_POSITION(position); -	config_func->device |= func_device[1]; - -	dev_dbg(vexpress_sysreg_dev, "func 0x%p = 0x%x, %d\n", config_func, -			config_func->template, config_func->device); - -	return config_func; +	writel(~0, vexpress_sysreg_base() + SYS_FLAGSCLR); +	writel(data, vexpress_sysreg_base() + SYS_FLAGSSET);  } -static void vexpress_sysreg_config_func_put(void *func) +unsigned int vexpress_get_mci_cardin(struct device *dev)  { -	kfree(func); +	return readl(vexpress_sysreg_base() + SYS_MCI) & SYS_MCI_CARDIN;  } -static int vexpress_sysreg_config_func_exec(void *func, int offset, -		bool write, u32 *data) +u32 vexpress_get_procid(int site)  { -	int status; -	struct vexpress_sysreg_config_func *config_func = func; -	u32 command; - -	if (WARN_ON(!vexpress_sysreg_base)) -		return -ENOENT; - -	command = readl(vexpress_sysreg_base + SYS_CFGCTRL); -	if (WARN_ON(command & SYS_CFGCTRL_START)) -		return -EBUSY; - -	command = SYS_CFGCTRL_START; -	command |= write ? SYS_CFGCTRL_WRITE : 0; -	command |= config_func->template; -	command |= SYS_CFGCTRL_DEVICE(config_func->device + offset); - -	/* Use a canary for reads */ -	if (!write) -		*data = 0xdeadbeef; - -	dev_dbg(vexpress_sysreg_dev, "command %x, data %x\n", -			command, *data); -	writel(*data, vexpress_sysreg_base + SYS_CFGDATA); -	writel(0, vexpress_sysreg_base + SYS_CFGSTAT); -	writel(command, vexpress_sysreg_base + SYS_CFGCTRL); -	mb(); - -	if (vexpress_sysreg_dev) { -		/* Schedule completion check */ -		if (!write) -			vexpress_sysreg_config_data = data; -		vexpress_sysreg_config_tries = 100; -		mod_timer(&vexpress_sysreg_config_timer, -				jiffies + usecs_to_jiffies(100)); -		status = VEXPRESS_CONFIG_STATUS_WAIT; -	} else { -		/* Early execution, no timer available, have to spin */ -		u32 cfgstat; - -		do { -			cpu_relax(); -			cfgstat = readl(vexpress_sysreg_base + SYS_CFGSTAT); -		} while (!cfgstat); - -		if (!write && (cfgstat & SYS_CFGSTAT_COMPLETE)) -			*data = readl(vexpress_sysreg_base + SYS_CFGDATA); -		status = VEXPRESS_CONFIG_STATUS_DONE; - -		if (cfgstat & SYS_CFGSTAT_ERR) -			status = -EINVAL; -	} +	if (site == VEXPRESS_SITE_MASTER) +		site = vexpress_sysreg_get_master(); -	return status; +	return readl(vexpress_sysreg_base() + (site == VEXPRESS_SITE_DB1 ? +			SYS_PROCID0 : SYS_PROCID1));  } -struct vexpress_config_bridge_info vexpress_sysreg_config_bridge_info = { -	.name = "vexpress-sysreg", -	.func_get = vexpress_sysreg_config_func_get, -	.func_put = vexpress_sysreg_config_func_put, -	.func_exec = vexpress_sysreg_config_func_exec, -}; - -static void vexpress_sysreg_config_complete(unsigned long data) +void __iomem *vexpress_get_24mhz_clock_base(void)  { -	int status = VEXPRESS_CONFIG_STATUS_DONE; -	u32 cfgstat = readl(vexpress_sysreg_base + SYS_CFGSTAT); - -	if (cfgstat & SYS_CFGSTAT_ERR) -		status = -EINVAL; -	if (!vexpress_sysreg_config_tries--) -		status = -ETIMEDOUT; - -	if (status < 0) { -		dev_err(vexpress_sysreg_dev, "error %d\n", status); -	} else if (!(cfgstat & SYS_CFGSTAT_COMPLETE)) { -		mod_timer(&vexpress_sysreg_config_timer, -				jiffies + usecs_to_jiffies(50)); -		return; -	} - -	if (vexpress_sysreg_config_data) { -		*vexpress_sysreg_config_data = readl(vexpress_sysreg_base + -				SYS_CFGDATA); -		dev_dbg(vexpress_sysreg_dev, "read data %x\n", -				*vexpress_sysreg_config_data); -		vexpress_sysreg_config_data = NULL; -	} - -	vexpress_config_complete(vexpress_sysreg_config_bridge, status); +	return vexpress_sysreg_base() + SYS_24MHZ;  } -void vexpress_sysreg_setup(struct device_node *node) -{ -	if (WARN_ON(!vexpress_sysreg_base)) -		return; - -	if (readl(vexpress_sysreg_base + SYS_MISC) & SYS_MISC_MASTERSITE) -		vexpress_master_site = VEXPRESS_SITE_DB2; -	else -		vexpress_master_site = VEXPRESS_SITE_DB1; - -	vexpress_sysreg_config_bridge = vexpress_config_bridge_register( -			node, &vexpress_sysreg_config_bridge_info); -	WARN_ON(!vexpress_sysreg_config_bridge); -} -  void __init vexpress_sysreg_early_init(void __iomem *base)  { -	vexpress_sysreg_base = base; -	vexpress_sysreg_setup(NULL); -} - -void __init vexpress_sysreg_of_early_init(void) -{ -	struct device_node *node; - -	if (vexpress_sysreg_base) -		return; +	__vexpress_sysreg_base = base; -	node = of_find_compatible_node(NULL, NULL, "arm,vexpress-sysreg"); -	if (node) { -		vexpress_sysreg_base = of_iomap(node, 0); -		vexpress_sysreg_setup(node); -	} +	vexpress_config_set_master(vexpress_sysreg_get_master());  } -#ifdef CONFIG_GPIOLIB - -#define VEXPRESS_SYSREG_GPIO(_name, _reg, _value) \ -	[VEXPRESS_GPIO_##_name] = { \ -		.reg = _reg, \ -		.value = _reg##_##_value, \ -	} +/* The sysreg block is just a random collection of various functions... */ -static struct vexpress_sysreg_gpio { -	unsigned long reg; -	u32 value; -} vexpress_sysreg_gpios[] = { -	VEXPRESS_SYSREG_GPIO(MMC_CARDIN,	SYS_MCI,	CARDIN), -	VEXPRESS_SYSREG_GPIO(MMC_WPROT,		SYS_MCI,	WPROT), -	VEXPRESS_SYSREG_GPIO(FLASH_WPn,		SYS_FLASH,	WPn), -	VEXPRESS_SYSREG_GPIO(LED0,		SYS_LED,	LED(0)), -	VEXPRESS_SYSREG_GPIO(LED1,		SYS_LED,	LED(1)), -	VEXPRESS_SYSREG_GPIO(LED2,		SYS_LED,	LED(2)), -	VEXPRESS_SYSREG_GPIO(LED3,		SYS_LED,	LED(3)), -	VEXPRESS_SYSREG_GPIO(LED4,		SYS_LED,	LED(4)), -	VEXPRESS_SYSREG_GPIO(LED5,		SYS_LED,	LED(5)), -	VEXPRESS_SYSREG_GPIO(LED6,		SYS_LED,	LED(6)), -	VEXPRESS_SYSREG_GPIO(LED7,		SYS_LED,	LED(7)), +static struct syscon_platform_data vexpress_sysreg_sys_id_pdata = { +	.label = "sys_id",  }; -static int vexpress_sysreg_gpio_direction_input(struct gpio_chip *chip, -				       unsigned offset) -{ -	return 0; -} - -static int vexpress_sysreg_gpio_get(struct gpio_chip *chip, -				       unsigned offset) -{ -	struct vexpress_sysreg_gpio *gpio = &vexpress_sysreg_gpios[offset]; -	u32 reg_value = readl(vexpress_sysreg_base + gpio->reg); - -	return !!(reg_value & gpio->value); -} - -static void vexpress_sysreg_gpio_set(struct gpio_chip *chip, -				       unsigned offset, int value) -{ -	struct vexpress_sysreg_gpio *gpio = &vexpress_sysreg_gpios[offset]; -	u32 reg_value = readl(vexpress_sysreg_base + gpio->reg); - -	if (value) -		reg_value |= gpio->value; -	else -		reg_value &= ~gpio->value; - -	writel(reg_value, vexpress_sysreg_base + gpio->reg); -} - -static int vexpress_sysreg_gpio_direction_output(struct gpio_chip *chip, -						unsigned offset, int value) -{ -	vexpress_sysreg_gpio_set(chip, offset, value); - -	return 0; -} - -static struct gpio_chip vexpress_sysreg_gpio_chip = { -	.label = "vexpress-sysreg", -	.direction_input = vexpress_sysreg_gpio_direction_input, -	.direction_output = vexpress_sysreg_gpio_direction_output, -	.get = vexpress_sysreg_gpio_get, -	.set = vexpress_sysreg_gpio_set, -	.ngpio = ARRAY_SIZE(vexpress_sysreg_gpios), -	.base = 0, +static struct bgpio_pdata vexpress_sysreg_sys_led_pdata = { +	.label = "sys_led", +	.base = -1, +	.ngpio = 8,  }; - -#define VEXPRESS_SYSREG_GREEN_LED(_name, _default_trigger, _gpio) \ -	{ \ -		.name = "v2m:green:"_name, \ -		.default_trigger = _default_trigger, \ -		.gpio = VEXPRESS_GPIO_##_gpio, \ -	} - -struct gpio_led vexpress_sysreg_leds[] = { -	VEXPRESS_SYSREG_GREEN_LED("user1",	"heartbeat",	LED0), -	VEXPRESS_SYSREG_GREEN_LED("user2",	"mmc0",		LED1), -	VEXPRESS_SYSREG_GREEN_LED("user3",	"cpu0",		LED2), -	VEXPRESS_SYSREG_GREEN_LED("user4",	"cpu1",		LED3), -	VEXPRESS_SYSREG_GREEN_LED("user5",	"cpu2",		LED4), -	VEXPRESS_SYSREG_GREEN_LED("user6",	"cpu3",		LED5), -	VEXPRESS_SYSREG_GREEN_LED("user7",	"cpu4",		LED6), -	VEXPRESS_SYSREG_GREEN_LED("user8",	"cpu5",		LED7), +static struct bgpio_pdata vexpress_sysreg_sys_mci_pdata = { +	.label = "sys_mci", +	.base = -1, +	.ngpio = 2,  }; -struct gpio_led_platform_data vexpress_sysreg_leds_pdata = { -	.num_leds = ARRAY_SIZE(vexpress_sysreg_leds), -	.leds = vexpress_sysreg_leds, +static struct bgpio_pdata vexpress_sysreg_sys_flash_pdata = { +	.label = "sys_flash", +	.base = -1, +	.ngpio = 1,  }; -#endif - +static struct syscon_platform_data vexpress_sysreg_sys_misc_pdata = { +	.label = "sys_misc", +}; -static ssize_t vexpress_sysreg_sys_id_show(struct device *dev, -		struct device_attribute *attr, char *buf) -{ -	return sprintf(buf, "0x%08x\n", readl(vexpress_sysreg_base + SYS_ID)); -} +static struct syscon_platform_data vexpress_sysreg_sys_procid_pdata = { +	.label = "sys_procid", +}; -DEVICE_ATTR(sys_id, S_IRUGO, vexpress_sysreg_sys_id_show, NULL); +static struct mfd_cell vexpress_sysreg_cells[] = { +	{ +		.name = "syscon", +		.num_resources = 1, +		.resources = (struct resource []) { +			DEFINE_RES_MEM(SYS_ID, 0x4), +		}, +		.platform_data = &vexpress_sysreg_sys_id_pdata, +		.pdata_size = sizeof(vexpress_sysreg_sys_id_pdata), +	}, { +		.name = "basic-mmio-gpio", +		.of_compatible = "arm,vexpress-sysreg,sys_led", +		.num_resources = 1, +		.resources = (struct resource []) { +			DEFINE_RES_MEM_NAMED(SYS_LED, 0x4, "dat"), +		}, +		.platform_data = &vexpress_sysreg_sys_led_pdata, +		.pdata_size = sizeof(vexpress_sysreg_sys_led_pdata), +	}, { +		.name = "basic-mmio-gpio", +		.of_compatible = "arm,vexpress-sysreg,sys_mci", +		.num_resources = 1, +		.resources = (struct resource []) { +			DEFINE_RES_MEM_NAMED(SYS_MCI, 0x4, "dat"), +		}, +		.platform_data = &vexpress_sysreg_sys_mci_pdata, +		.pdata_size = sizeof(vexpress_sysreg_sys_mci_pdata), +	}, { +		.name = "basic-mmio-gpio", +		.of_compatible = "arm,vexpress-sysreg,sys_flash", +		.num_resources = 1, +		.resources = (struct resource []) { +			DEFINE_RES_MEM_NAMED(SYS_FLASH, 0x4, "dat"), +		}, +		.platform_data = &vexpress_sysreg_sys_flash_pdata, +		.pdata_size = sizeof(vexpress_sysreg_sys_flash_pdata), +	}, { +		.name = "syscon", +		.num_resources = 1, +		.resources = (struct resource []) { +			DEFINE_RES_MEM(SYS_MISC, 0x4), +		}, +		.platform_data = &vexpress_sysreg_sys_misc_pdata, +		.pdata_size = sizeof(vexpress_sysreg_sys_misc_pdata), +	}, { +		.name = "syscon", +		.num_resources = 1, +		.resources = (struct resource []) { +			DEFINE_RES_MEM(SYS_PROCID0, 0x8), +		}, +		.platform_data = &vexpress_sysreg_sys_procid_pdata, +		.pdata_size = sizeof(vexpress_sysreg_sys_procid_pdata), +	}, { +		.name = "vexpress-syscfg", +		.num_resources = 1, +		.resources = (struct resource []) { +			DEFINE_RES_MEM(SYS_CFGDATA, 0xc), +		}, +	} +};  static int vexpress_sysreg_probe(struct platform_device *pdev)  { -	int err; -	struct resource *res = platform_get_resource(pdev, -			IORESOURCE_MEM, 0); - -	if (!devm_request_mem_region(&pdev->dev, res->start, -			resource_size(res), pdev->name)) { -		dev_err(&pdev->dev, "Failed to request memory region!\n"); -		return -EBUSY; -	} +	struct resource *mem; +	void __iomem *base; +	struct bgpio_chip *mmc_gpio_chip; +	u32 dt_hbi; -	if (!vexpress_sysreg_base) { -		vexpress_sysreg_base = devm_ioremap(&pdev->dev, res->start, -				resource_size(res)); -		vexpress_sysreg_setup(pdev->dev.of_node); -	} +	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); +	if (!mem) +		return -EINVAL; -	if (!vexpress_sysreg_base) { -		dev_err(&pdev->dev, "Failed to obtain base address!\n"); -		return -EFAULT; -	} +	base = devm_ioremap(&pdev->dev, mem->start, resource_size(mem)); +	if (!base) +		return -ENOMEM; -	setup_timer(&vexpress_sysreg_config_timer, -			vexpress_sysreg_config_complete, 0); +	vexpress_config_set_master(vexpress_sysreg_get_master()); -	vexpress_sysreg_dev = &pdev->dev; +	/* Confirm board type against DT property, if available */ +	if (of_property_read_u32(of_allnodes, "arm,hbi", &dt_hbi) == 0) { +		u32 id = vexpress_get_procid(VEXPRESS_SITE_MASTER); +		u32 hbi = (id >> SYS_PROCIDx_HBI_SHIFT) & SYS_HBI_MASK; -#ifdef CONFIG_GPIOLIB -	vexpress_sysreg_gpio_chip.dev = &pdev->dev; -	err = gpiochip_add(&vexpress_sysreg_gpio_chip); -	if (err) { -		vexpress_config_bridge_unregister( -				vexpress_sysreg_config_bridge); -		dev_err(&pdev->dev, "Failed to register GPIO chip! (%d)\n", -				err); -		return err; +		if (WARN_ON(dt_hbi != hbi)) +			dev_warn(&pdev->dev, "DT HBI (%x) is not matching hardware (%x)!\n", +					dt_hbi, hbi);  	} -	platform_device_register_data(vexpress_sysreg_dev, "leds-gpio", -			PLATFORM_DEVID_AUTO, &vexpress_sysreg_leds_pdata, -			sizeof(vexpress_sysreg_leds_pdata)); -#endif - -	device_create_file(vexpress_sysreg_dev, &dev_attr_sys_id); - -	return 0; +	/* +	 * Duplicated SYS_MCI pseudo-GPIO controller for compatibility with +	 * older trees using sysreg node for MMC control lines. +	 */ +	mmc_gpio_chip = devm_kzalloc(&pdev->dev, sizeof(*mmc_gpio_chip), +			GFP_KERNEL); +	if (!mmc_gpio_chip) +		return -ENOMEM; +	bgpio_init(mmc_gpio_chip, &pdev->dev, 0x4, base + SYS_MCI, +			NULL, NULL, NULL, NULL, 0); +	mmc_gpio_chip->gc.ngpio = 2; +	gpiochip_add(&mmc_gpio_chip->gc); + +	return mfd_add_devices(&pdev->dev, PLATFORM_DEVID_AUTO, +			vexpress_sysreg_cells, +			ARRAY_SIZE(vexpress_sysreg_cells), mem, 0, NULL);  }  static const struct of_device_id vexpress_sysreg_match[] = { @@ -522,7 +265,12 @@ static struct platform_driver vexpress_sysreg_driver = {  static int __init vexpress_sysreg_init(void)  { -	vexpress_sysreg_of_early_init(); +	struct device_node *node; + +	/* Need the sysreg early, before any other device... */ +	for_each_matching_node(node, vexpress_sysreg_match) +		of_platform_device_create(node, NULL, NULL); +  	return platform_driver_register(&vexpress_sysreg_driver);  }  core_initcall(vexpress_sysreg_init);  | 
