Commit 974cc7b9 authored by Pawel Moll's avatar Pawel Moll

mfd: vexpress: Define the device as MFD cells

This patch - finally, after over 6 months! :-( - addresses
Samuel's request to split the vexpress-sysreg driver into
smaller portions and define the device in a form of MFD
cells:

* LEDs code has been completely removed and replaced with
  "gpio-leds" nodes in the tree (referencing dedicated
  GPIO subnodes in sysreg - bindings documentation updated);
  this also better fits the reality as some variants of the
  motherboard don't have all the LEDs populated

* syscfg bridge code has been extracted into a separate
  driver (placed in drivers/misc for no better place)

* all the ID & MISC registers are defined as sysconf
  making them available for other drivers should they need
  to use them (and also to the user via /sys/kernel/debug/regmap
  which can be helpful in platform debugging)
Signed-off-by: default avatarPawel Moll <pawel.moll@arm.com>
Acked-by: default avatarLee Jones <lee.jones@linaro.org>
parent 29f9b6cf
...@@ -8,6 +8,8 @@ interrupt generation, MMC and NOR Flash control etc. ...@@ -8,6 +8,8 @@ interrupt generation, MMC and NOR Flash control etc.
Required node properties: Required node properties:
- compatible value : = "arm,vexpress,sysreg"; - compatible value : = "arm,vexpress,sysreg";
- reg : physical base address and the size of the registers window - reg : physical base address and the size of the registers window
Deprecated properties, replaced by GPIO subnodes (see below):
- gpio-controller : specifies that the node is a GPIO controller - gpio-controller : specifies that the node is a GPIO controller
- #gpio-cells : size of the GPIO specifier, should be 2: - #gpio-cells : size of the GPIO specifier, should be 2:
- first cell is the pseudo-GPIO line number: - first cell is the pseudo-GPIO line number:
...@@ -16,14 +18,44 @@ Required node properties: ...@@ -16,14 +18,44 @@ Required node properties:
2 - NOR FLASH WPn 2 - NOR FLASH WPn
- second cell can take standard GPIO flags (currently ignored). - second cell can take standard GPIO flags (currently ignored).
Control registers providing pseudo-GPIO lines must be represented
by subnodes, each of them requiring the following properties:
- compatible value : one of
"arm,vexpress-sysreg,sys_led"
"arm,vexpress-sysreg,sys_mci"
"arm,vexpress-sysreg,sys_flash"
- gpio-controller : makes the node a GPIO controller
- #gpio-cells : size of the GPIO specifier, must be 2:
- first cell is the function number:
- for sys_led : 0..7 = LED 0..7
- for sys_mci : 0 = MMC CARDIN, 1 = MMC WPROT
- for sys_flash : 0 = NOR FLASH WPn
- second cell can take standard GPIO flags (currently ignored).
Example: Example:
v2m_sysreg: sysreg@10000000 { v2m_sysreg: sysreg@10000000 {
compatible = "arm,vexpress-sysreg"; compatible = "arm,vexpress-sysreg";
reg = <0x10000000 0x1000>; reg = <0x10000000 0x1000>;
v2m_led_gpios: sys_led@08 {
compatible = "arm,vexpress-sysreg,sys_led";
gpio-controller; gpio-controller;
#gpio-cells = <2>; #gpio-cells = <2>;
}; };
v2m_mmc_gpios: sys_mci@48 {
compatible = "arm,vexpress-sysreg,sys_mci";
gpio-controller;
#gpio-cells = <2>;
};
v2m_flash_gpios: sys_flash@4c {
compatible = "arm,vexpress-sysreg,sys_flash";
gpio-controller;
#gpio-cells = <2>;
};
};
This block also can also act a bridge to the platform's configuration This block also can also act a bridge to the platform's configuration
bus via "system control" interface, addressing devices with site number, bus via "system control" interface, addressing devices with site number,
position in the board stack, config controller, function and device position in the board stack, config controller, function and device
......
...@@ -74,9 +74,25 @@ iofpga@3,00000000 { ...@@ -74,9 +74,25 @@ iofpga@3,00000000 {
v2m_sysreg: sysreg@010000 { v2m_sysreg: sysreg@010000 {
compatible = "arm,vexpress-sysreg"; compatible = "arm,vexpress-sysreg";
reg = <0x010000 0x1000>; reg = <0x010000 0x1000>;
v2m_led_gpios: sys_led@08 {
compatible = "arm,vexpress-sysreg,sys_led";
gpio-controller;
#gpio-cells = <2>;
};
v2m_mmc_gpios: sys_mci@48 {
compatible = "arm,vexpress-sysreg,sys_mci";
gpio-controller;
#gpio-cells = <2>;
};
v2m_flash_gpios: sys_flash@4c {
compatible = "arm,vexpress-sysreg,sys_flash";
gpio-controller; gpio-controller;
#gpio-cells = <2>; #gpio-cells = <2>;
}; };
};
v2m_sysctl: sysctl@020000 { v2m_sysctl: sysctl@020000 {
compatible = "arm,sp810", "arm,primecell"; compatible = "arm,sp810", "arm,primecell";
...@@ -113,8 +129,8 @@ mmci@050000 { ...@@ -113,8 +129,8 @@ mmci@050000 {
compatible = "arm,pl180", "arm,primecell"; compatible = "arm,pl180", "arm,primecell";
reg = <0x050000 0x1000>; reg = <0x050000 0x1000>;
interrupts = <9 10>; interrupts = <9 10>;
cd-gpios = <&v2m_sysreg 0 0>; cd-gpios = <&v2m_mmc_gpios 0 0>;
wp-gpios = <&v2m_sysreg 1 0>; wp-gpios = <&v2m_mmc_gpios 1 0>;
max-frequency = <12000000>; max-frequency = <12000000>;
vmmc-supply = <&v2m_fixed_3v3>; vmmc-supply = <&v2m_fixed_3v3>;
clocks = <&v2m_clk24mhz>, <&smbclk>; clocks = <&v2m_clk24mhz>, <&smbclk>;
...@@ -265,6 +281,58 @@ v2m_refclk32khz: refclk32khz { ...@@ -265,6 +281,58 @@ v2m_refclk32khz: refclk32khz {
clock-output-names = "v2m:refclk32khz"; clock-output-names = "v2m:refclk32khz";
}; };
leds {
compatible = "gpio-leds";
user@1 {
label = "v2m:green:user1";
gpios = <&v2m_led_gpios 0 0>;
linux,default-trigger = "heartbeat";
};
user@2 {
label = "v2m:green:user2";
gpios = <&v2m_led_gpios 1 0>;
linux,default-trigger = "mmc0";
};
user@3 {
label = "v2m:green:user3";
gpios = <&v2m_led_gpios 2 0>;
linux,default-trigger = "cpu0";
};
user@4 {
label = "v2m:green:user4";
gpios = <&v2m_led_gpios 3 0>;
linux,default-trigger = "cpu1";
};
user@5 {
label = "v2m:green:user5";
gpios = <&v2m_led_gpios 4 0>;
linux,default-trigger = "cpu2";
};
user@6 {
label = "v2m:green:user6";
gpios = <&v2m_led_gpios 5 0>;
linux,default-trigger = "cpu3";
};
user@7 {
label = "v2m:green:user7";
gpios = <&v2m_led_gpios 6 0>;
linux,default-trigger = "cpu4";
};
user@8 {
label = "v2m:green:user8";
gpios = <&v2m_led_gpios 7 0>;
linux,default-trigger = "cpu5";
};
};
mcc { mcc {
compatible = "arm,vexpress,config-bus"; compatible = "arm,vexpress,config-bus";
arm,vexpress,config-bridge = <&v2m_sysreg>; arm,vexpress,config-bridge = <&v2m_sysreg>;
......
...@@ -73,9 +73,25 @@ iofpga@7,00000000 { ...@@ -73,9 +73,25 @@ iofpga@7,00000000 {
v2m_sysreg: sysreg@00000 { v2m_sysreg: sysreg@00000 {
compatible = "arm,vexpress-sysreg"; compatible = "arm,vexpress-sysreg";
reg = <0x00000 0x1000>; reg = <0x00000 0x1000>;
v2m_led_gpios: sys_led@08 {
compatible = "arm,vexpress-sysreg,sys_led";
gpio-controller;
#gpio-cells = <2>;
};
v2m_mmc_gpios: sys_mci@48 {
compatible = "arm,vexpress-sysreg,sys_mci";
gpio-controller;
#gpio-cells = <2>;
};
v2m_flash_gpios: sys_flash@4c {
compatible = "arm,vexpress-sysreg,sys_flash";
gpio-controller; gpio-controller;
#gpio-cells = <2>; #gpio-cells = <2>;
}; };
};
v2m_sysctl: sysctl@01000 { v2m_sysctl: sysctl@01000 {
compatible = "arm,sp810", "arm,primecell"; compatible = "arm,sp810", "arm,primecell";
...@@ -112,8 +128,8 @@ mmci@05000 { ...@@ -112,8 +128,8 @@ mmci@05000 {
compatible = "arm,pl180", "arm,primecell"; compatible = "arm,pl180", "arm,primecell";
reg = <0x05000 0x1000>; reg = <0x05000 0x1000>;
interrupts = <9 10>; interrupts = <9 10>;
cd-gpios = <&v2m_sysreg 0 0>; cd-gpios = <&v2m_mmc_gpios 0 0>;
wp-gpios = <&v2m_sysreg 1 0>; wp-gpios = <&v2m_mmc_gpios 1 0>;
max-frequency = <12000000>; max-frequency = <12000000>;
vmmc-supply = <&v2m_fixed_3v3>; vmmc-supply = <&v2m_fixed_3v3>;
clocks = <&v2m_clk24mhz>, <&smbclk>; clocks = <&v2m_clk24mhz>, <&smbclk>;
...@@ -264,6 +280,58 @@ v2m_refclk32khz: refclk32khz { ...@@ -264,6 +280,58 @@ v2m_refclk32khz: refclk32khz {
clock-output-names = "v2m:refclk32khz"; clock-output-names = "v2m:refclk32khz";
}; };
leds {
compatible = "gpio-leds";
user@1 {
label = "v2m:green:user1";
gpios = <&v2m_led_gpios 0 0>;
linux,default-trigger = "heartbeat";
};
user@2 {
label = "v2m:green:user2";
gpios = <&v2m_led_gpios 1 0>;
linux,default-trigger = "mmc0";
};
user@3 {
label = "v2m:green:user3";
gpios = <&v2m_led_gpios 2 0>;
linux,default-trigger = "cpu0";
};
user@4 {
label = "v2m:green:user4";
gpios = <&v2m_led_gpios 3 0>;
linux,default-trigger = "cpu1";
};
user@5 {
label = "v2m:green:user5";
gpios = <&v2m_led_gpios 4 0>;
linux,default-trigger = "cpu2";
};
user@6 {
label = "v2m:green:user6";
gpios = <&v2m_led_gpios 5 0>;
linux,default-trigger = "cpu3";
};
user@7 {
label = "v2m:green:user7";
gpios = <&v2m_led_gpios 6 0>;
linux,default-trigger = "cpu4";
};
user@8 {
label = "v2m:green:user8";
gpios = <&v2m_led_gpios 7 0>;
linux,default-trigger = "cpu5";
};
};
mcc { mcc {
compatible = "arm,vexpress,config-bus"; compatible = "arm,vexpress,config-bus";
arm,vexpress,config-bridge = <&v2m_sysreg>; arm,vexpress,config-bridge = <&v2m_sysreg>;
......
...@@ -160,7 +160,7 @@ static void __init ct_ca9x4_init(void) ...@@ -160,7 +160,7 @@ static void __init ct_ca9x4_init(void)
amba_device_register(ct_ca9x4_amba_devs[i], &iomem_resource); amba_device_register(ct_ca9x4_amba_devs[i], &iomem_resource);
platform_device_register(&pmu_device); platform_device_register(&pmu_device);
vexpress_sysreg_config_device_register(&osc1_device); vexpress_syscfg_device_register(&osc1_device);
} }
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
......
...@@ -201,8 +201,9 @@ static struct platform_device v2m_cf_device = { ...@@ -201,8 +201,9 @@ static struct platform_device v2m_cf_device = {
static struct mmci_platform_data v2m_mmci_data = { static struct mmci_platform_data v2m_mmci_data = {
.ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
.gpio_wp = VEXPRESS_GPIO_MMC_WPROT, .status = vexpress_get_mci_cardin,
.gpio_cd = VEXPRESS_GPIO_MMC_CARDIN, .gpio_cd = -1,
.gpio_wp = -1,
}; };
static struct resource v2m_sysreg_resources[] = { static struct resource v2m_sysreg_resources[] = {
...@@ -351,10 +352,10 @@ static void __init v2m_init(void) ...@@ -351,10 +352,10 @@ static void __init v2m_init(void)
for (i = 0; i < ARRAY_SIZE(v2m_amba_devs); i++) for (i = 0; i < ARRAY_SIZE(v2m_amba_devs); i++)
amba_device_register(v2m_amba_devs[i], &iomem_resource); amba_device_register(v2m_amba_devs[i], &iomem_resource);
vexpress_sysreg_config_device_register(&v2m_muxfpga_device); vexpress_syscfg_device_register(&v2m_muxfpga_device);
vexpress_sysreg_config_device_register(&v2m_shutdown_device); vexpress_syscfg_device_register(&v2m_shutdown_device);
vexpress_sysreg_config_device_register(&v2m_reboot_device); vexpress_syscfg_device_register(&v2m_reboot_device);
vexpress_sysreg_config_device_register(&v2m_dvimode_device); vexpress_syscfg_device_register(&v2m_dvimode_device);
ct_desc->init_tile(); ct_desc->init_tile();
} }
...@@ -409,8 +410,6 @@ void __init v2m_dt_init_early(void) ...@@ -409,8 +410,6 @@ void __init v2m_dt_init_early(void)
{ {
u32 dt_hbi; u32 dt_hbi;
vexpress_sysreg_of_early_init();
/* Confirm board type against DT property, if available */ /* Confirm board type against DT property, if available */
if (of_property_read_u32(of_allnodes, "arm,hbi", &dt_hbi) == 0) { if (of_property_read_u32(of_allnodes, "arm,hbi", &dt_hbi) == 0) {
u32 hbi = vexpress_get_hbi(VEXPRESS_SITE_MASTER); u32 hbi = vexpress_get_hbi(VEXPRESS_SITE_MASTER);
......
...@@ -1227,12 +1227,17 @@ config MCP_UCB1200_TS ...@@ -1227,12 +1227,17 @@ config MCP_UCB1200_TS
endmenu endmenu
config VEXPRESS_CONFIG config MFD_VEXPRESS_SYSREG
bool "ARM Versatile Express platform infrastructure" bool "Versatile Express System Registers"
depends on ARM || ARM64 depends on VEXPRESS_CONFIG
default y
select CLKSRC_MMIO
select GPIO_GENERIC_PLATFORM
select MFD_CORE
select MFD_SYSCON
help help
Platform configuration infrastructure for the ARM Ltd. System Registers are the platform configuration block
Versatile Express. on the ARM Ltd. Versatile Express board.
endmenu endmenu
endif endif
...@@ -161,7 +161,7 @@ obj-$(CONFIG_MFD_RC5T583) += rc5t583.o rc5t583-irq.o ...@@ -161,7 +161,7 @@ obj-$(CONFIG_MFD_RC5T583) += rc5t583.o rc5t583-irq.o
obj-$(CONFIG_MFD_SEC_CORE) += sec-core.o sec-irq.o obj-$(CONFIG_MFD_SEC_CORE) += sec-core.o sec-irq.o
obj-$(CONFIG_MFD_SYSCON) += syscon.o obj-$(CONFIG_MFD_SYSCON) += syscon.o
obj-$(CONFIG_MFD_LM3533) += lm3533-core.o lm3533-ctrlbank.o obj-$(CONFIG_MFD_LM3533) += lm3533-core.o lm3533-ctrlbank.o
obj-$(CONFIG_VEXPRESS_CONFIG) += vexpress-sysreg.o obj-$(CONFIG_MFD_VEXPRESS_SYSREG) += vexpress-sysreg.o
obj-$(CONFIG_MFD_RETU) += retu-mfd.o obj-$(CONFIG_MFD_RETU) += retu-mfd.o
obj-$(CONFIG_MFD_AS3711) += as3711.o obj-$(CONFIG_MFD_AS3711) += as3711.o
obj-$(CONFIG_MFD_AS3722) += as3722.o obj-$(CONFIG_MFD_AS3722) += as3722.o
......
This diff is collapsed.
...@@ -515,6 +515,15 @@ config SRAM ...@@ -515,6 +515,15 @@ config SRAM
the genalloc API. It is supposed to be used for small on-chip SRAM the genalloc API. It is supposed to be used for small on-chip SRAM
areas found on many SoCs. areas found on many SoCs.
config VEXPRESS_SYSCFG
bool "Versatile Express System Configuration driver"
depends on VEXPRESS_CONFIG
default y
help
ARM Ltd. Versatile Express uses specialised platform configuration
bus. System Configuration interface is one of the possible means
of generating transactions on this bus.
source "drivers/misc/c2port/Kconfig" source "drivers/misc/c2port/Kconfig"
source "drivers/misc/eeprom/Kconfig" source "drivers/misc/eeprom/Kconfig"
source "drivers/misc/cb710/Kconfig" source "drivers/misc/cb710/Kconfig"
......
...@@ -55,3 +55,4 @@ obj-$(CONFIG_SRAM) += sram.o ...@@ -55,3 +55,4 @@ obj-$(CONFIG_SRAM) += sram.o
obj-y += mic/ obj-y += mic/
obj-$(CONFIG_GENWQE) += genwqe/ obj-$(CONFIG_GENWQE) += genwqe/
obj-$(CONFIG_ECHO) += echo/ obj-$(CONFIG_ECHO) += echo/
obj-$(CONFIG_VEXPRESS_SYSCFG) += vexpress-syscfg.o
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* Copyright (C) 2014 ARM Limited
*/
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/syscore_ops.h>
#include <linux/vexpress.h>
#define SYS_CFGDATA 0x0
#define SYS_CFGCTRL 0x4
#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 0x8
#define SYS_CFGSTAT_ERR (1 << 1)
#define SYS_CFGSTAT_COMPLETE (1 << 0)
struct vexpress_syscfg {
struct device *dev;
void __iomem *base;
struct list_head funcs;
};
struct vexpress_syscfg_func {
struct list_head list;
struct vexpress_syscfg *syscfg;
struct regmap *regmap;
int num_templates;
u32 template[0]; /* Keep it last! */
};
static int vexpress_syscfg_exec(struct vexpress_syscfg_func *func,
int index, bool write, u32 *data)
{
struct vexpress_syscfg *syscfg = func->syscfg;
u32 command, status;
int tries;
long timeout;
if (WARN_ON(index > func->num_templates))
return -EINVAL;
command = readl(syscfg->base + SYS_CFGCTRL);
if (WARN_ON(command & SYS_CFGCTRL_START))
return -EBUSY;
command = func->template[index];
command |= SYS_CFGCTRL_START;
command |= write ? SYS_CFGCTRL_WRITE : 0;
/* Use a canary for reads */
if (!write)
*data = 0xdeadbeef;
dev_dbg(syscfg->dev, "func %p, command %x, data %x\n",
func, command, *data);
writel(*data, syscfg->base + SYS_CFGDATA);
writel(0, syscfg->base + SYS_CFGSTAT);
writel(command, syscfg->base + SYS_CFGCTRL);
mb();
/* The operation can take ages... Go to sleep, 100us initially */
tries = 100;
timeout = 100;
do {
if (!irqs_disabled()) {
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(usecs_to_jiffies(timeout));
if (signal_pending(current))
return -EINTR;
} else {
udelay(timeout);
}
status = readl(syscfg->base + SYS_CFGSTAT);
if (status & SYS_CFGSTAT_ERR)
return -EFAULT;
if (timeout > 20)
timeout -= 20;
} while (--tries && !(status & SYS_CFGSTAT_COMPLETE));
if (WARN_ON_ONCE(!tries))
return -ETIMEDOUT;
if (!write) {
*data = readl(syscfg->base + SYS_CFGDATA);
dev_dbg(syscfg->dev, "func %p, read data %x\n", func, *data);
}
return 0;
}
static int vexpress_syscfg_read(void *context, unsigned int index,
unsigned int *val)
{
struct vexpress_syscfg_func *func = context;
return vexpress_syscfg_exec(func, index, false, val);
}
static int vexpress_syscfg_write(void *context, unsigned int index,
unsigned int val)
{
struct vexpress_syscfg_func *func = context;
return vexpress_syscfg_exec(func, index, true, &val);
}
struct regmap_config vexpress_syscfg_regmap_config = {
.lock = vexpress_config_lock,
.unlock = vexpress_config_unlock,
.reg_bits = 32,
.val_bits = 32,
.reg_read = vexpress_syscfg_read,
.reg_write = vexpress_syscfg_write,
.reg_format_endian = REGMAP_ENDIAN_LITTLE,
.val_format_endian = REGMAP_ENDIAN_LITTLE,
};
static struct regmap *vexpress_syscfg_regmap_init(struct device *dev,
void *context)
{
struct platform_device *pdev = to_platform_device(dev);
struct vexpress_syscfg *syscfg = context;
struct vexpress_syscfg_func *func;
struct property *prop;
const __be32 *val = NULL;
__be32 energy_quirk[4];
int num;
u32 site, position, dcc;
int i;
if (dev->of_node) {
int err = vexpress_config_get_topo(dev->of_node, &site,
&position, &dcc);
if (err)
return ERR_PTR(err);
prop = of_find_property(dev->of_node,
"arm,vexpress-sysreg,func", NULL);
if (!prop)
return ERR_PTR(-EINVAL);
num = prop->length / sizeof(u32) / 2;
val = prop->value;
} else {
if (pdev->num_resources != 1 ||
pdev->resource[0].flags != IORESOURCE_BUS)
return ERR_PTR(-EFAULT);
site = pdev->resource[0].start;
if (site == VEXPRESS_SITE_MASTER)
site = vexpress_config_get_master();
position = 0;
dcc = 0;
num = 1;
}
/*
* "arm,vexpress-energy" function used to be described
* by its first device only, now it requires both
*/
if (num == 1 && of_device_is_compatible(dev->of_node,
"arm,vexpress-energy")) {
num = 2;
energy_quirk[0] = *val;
energy_quirk[2] = *val++;
energy_quirk[1] = *val;
energy_quirk[3] = cpu_to_be32(be32_to_cpup(val) + 1);
val = energy_quirk;
}
func = kzalloc(sizeof(*func) + sizeof(*func->template) * num,
GFP_KERNEL);
if (!func)
return NULL;
func->syscfg = syscfg;
func->num_templates = num;
for (i = 0; i < num; i++) {
u32 function, device;
if (dev->of_node) {
function = be32_to_cpup(val++);
device = be32_to_cpup(val++);
} else {
function = pdev->resource[0].end;
device = pdev->id;
}
dev_dbg(dev, "func %p: %u/%u/%u/%u/%u\n",
func, site, position, dcc,
function, device);
func->template[i] = SYS_CFGCTRL_DCC(dcc);
func->template[i] |= SYS_CFGCTRL_SITE(site);
func->template[i] |= SYS_CFGCTRL_POSITION(position);
func->template[i] |= SYS_CFGCTRL_FUNC(function);
func->template[i] |= SYS_CFGCTRL_DEVICE(device);
}
vexpress_syscfg_regmap_config.max_register = num - 1;
func->regmap = regmap_init(dev, NULL, func,
&vexpress_syscfg_regmap_config);
if (IS_ERR(func->regmap))
kfree(func);
else
list_add(&func->list, &syscfg->funcs);
return func->regmap;
}
static void vexpress_syscfg_regmap_exit(struct regmap *regmap, void *context)
{
struct vexpress_syscfg *syscfg = context;
struct vexpress_syscfg_func *func, *tmp;
regmap_exit(regmap);
list_for_each_entry_safe(func, tmp, &syscfg->funcs, list) {
if (func->regmap == regmap) {
list_del(&syscfg->funcs);
kfree(func);
break;
}
}
}
static struct vexpress_config_bridge_ops vexpress_syscfg_bridge_ops = {
.regmap_init = vexpress_syscfg_regmap_init,
.regmap_exit = vexpress_syscfg_regmap_exit,
};
/* Non-DT hack, to be gone... */
static struct device *vexpress_syscfg_bridge;
int vexpress_syscfg_device_register(struct platform_device *pdev)
{
pdev->dev.parent = vexpress_syscfg_bridge;
return platform_device_register(pdev);
}
int vexpress_syscfg_probe(struct platform_device *pdev)
{
struct vexpress_syscfg *syscfg;
struct resource *res;
struct device *bridge;
syscfg = devm_kzalloc(&pdev->dev, sizeof(*syscfg), GFP_KERNEL);
if (!syscfg)
return -ENOMEM;
syscfg->dev = &pdev->dev;
INIT_LIST_HEAD(&syscfg->funcs);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!devm_request_mem_region(&pdev->dev, res->start,
resource_size(res), pdev->name))
return -EBUSY;
syscfg->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
if (!syscfg->base)
return -EFAULT;
/* Must use dev.parent (MFD), as that's where DT phandle points at... */
bridge = vexpress_config_bridge_register(pdev->dev.parent,
&vexpress_syscfg_bridge_ops, syscfg);
if (IS_ERR(bridge))
return PTR_ERR(bridge);
/* Non-DT case */
if (!pdev->dev.of_node)
vexpress_syscfg_bridge = bridge;
return 0;
}
static const struct platform_device_id vexpress_syscfg_id_table[] = {
{ "vexpress-syscfg", },
{},
};
static struct platform_driver vexpress_syscfg_driver = {
.driver.name = "vexpress-syscfg",
.id_table = vexpress_syscfg_id_table,
.probe = vexpress_syscfg_probe,
};
static int __init vexpress_syscfg_init(void)
{
return platform_driver_register(&vexpress_syscfg_driver);
}
core_initcall(vexpress_syscfg_init);
...@@ -24,18 +24,6 @@ ...@@ -24,18 +24,6 @@
#define VEXPRESS_SITE_DB2 2 #define VEXPRESS_SITE_DB2 2
#define VEXPRESS_SITE_MASTER 0xf #define VEXPRESS_SITE_MASTER 0xf
#define VEXPRESS_GPIO_MMC_CARDIN 0
#define VEXPRESS_GPIO_MMC_WPROT 1
#define VEXPRESS_GPIO_FLASH_WPn 2
#define VEXPRESS_GPIO_LED0 3
#define VEXPRESS_GPIO_LED1 4
#define VEXPRESS_GPIO_LED2 5
#define VEXPRESS_GPIO_LED3 6
#define VEXPRESS_GPIO_LED4 7
#define VEXPRESS_GPIO_LED5 8
#define VEXPRESS_GPIO_LED6 9
#define VEXPRESS_GPIO_LED7 10
#define VEXPRESS_RES_FUNC(_site, _func) \ #define VEXPRESS_RES_FUNC(_site, _func) \
{ \ { \
.start = (_site), \ .start = (_site), \
...@@ -70,14 +58,14 @@ struct regmap *devm_regmap_init_vexpress_config(struct device *dev); ...@@ -70,14 +58,14 @@ struct regmap *devm_regmap_init_vexpress_config(struct device *dev);
/* Platform control */ /* Platform control */
unsigned int vexpress_get_mci_cardin(struct device *dev);
u32 vexpress_get_procid(int site); u32 vexpress_get_procid(int site);
u32 vexpress_get_hbi(int site); u32 vexpress_get_hbi(int site);
void *vexpress_get_24mhz_clock_base(void); void *vexpress_get_24mhz_clock_base(void);
void vexpress_flags_set(u32 data); void vexpress_flags_set(u32 data);
void vexpress_sysreg_early_init(void __iomem *base); void vexpress_sysreg_early_init(void __iomem *base);
void vexpress_sysreg_of_early_init(void); int vexpress_syscfg_device_register(struct platform_device *pdev);
int vexpress_sysreg_config_device_register(struct platform_device *pdev);
/* Clocks */ /* Clocks */
......
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