This patch series mainly adds an syscon driver which is used to access
general system controller registers like FSL IOMUXC GPR and ANATOP,
after that, we convert all the exist private access general registers code to use
standard API from regmap to access registers.
Finally we remove the old mfd anatop driver which is only for anatop register
access.
The patch series is based on linus's tree 3.6-rc3 since commit 9160338.
Dong Aisheng (7):
mfd: add syscon driver based on regmap
ARM: imx6q: add iomuxc gpr support into syscon
ARM: imx6q: add anatop support into syscon
regulator: anatop-regulator: convert to use syscon to access anatop
register
ARM: imx6q: convert to use syscon to access anatop registers
ARM: dts: imx6q: add simple-bus compatible string for anatop
mfd: anatop-mfd: remove anatop driver
.../devicetree/bindings/mfd/imx-syscon.txt | 11 +
arch/arm/boot/dts/imx6q.dtsi | 15 +-
arch/arm/mach-imx/Kconfig | 2 +-
arch/arm/mach-imx/mach-imx6q.c | 43 ++--
drivers/mfd/Kconfig | 13 +-
drivers/mfd/Makefile | 2 +-
drivers/mfd/anatop-mfd.c | 124 --------
drivers/mfd/syscon.c | 169 +++++++++++
drivers/regulator/Kconfig | 2 +-
drivers/regulator/anatop-regulator.c | 25 +-
include/linux/fsl/imx6q-iomuxc-gpr.h | 319 ++++++++++++++++++++
include/linux/mfd/anatop.h | 40 ---
include/linux/mfd/syscon.h | 22 ++
13 files changed, 576 insertions(+), 211 deletions(-)
create mode 100644 Documentation/devicetree/bindings/mfd/imx-syscon.txt
delete mode 100644 drivers/mfd/anatop-mfd.c
create mode 100644 drivers/mfd/syscon.c
create mode 100644 include/linux/fsl/imx6q-iomuxc-gpr.h
delete mode 100644 include/linux/mfd/anatop.h
create mode 100644 include/linux/mfd/syscon.h
From: Dong Aisheng <[email protected]>
There're a few anatop registers need to be accessed by different modules.
Add anatop registers into syscon support for easy access.
Signed-off-by: Dong Aisheng <[email protected]>
---
arch/arm/boot/dts/imx6q.dtsi | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/arm/boot/dts/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi
index bea21bc..db3fa15 100644
--- a/arch/arm/boot/dts/imx6q.dtsi
+++ b/arch/arm/boot/dts/imx6q.dtsi
@@ -378,8 +378,8 @@
interrupts = <0 87 0x04 0 88 0x04>;
};
- anatop@020c8000 {
- compatible = "fsl,imx6q-anatop";
+ anatop: anatop@020c8000 {
+ compatible = "fsl,imx6q-anatop", "syscon";
reg = <0x020c8000 0x1000>;
interrupts = <0 49 0x04 0 54 0x04 0 127 0x04>;
--
1.7.0.4
From: Dong Aisheng <[email protected]>
Using syscon to access anatop register.
Acked-by: Mark Brown <[email protected]>
Signed-off-by: Dong Aisheng <[email protected]>
---
ChangeLog v1-v2:
* update to use generic regmap api
---
arch/arm/boot/dts/imx6q.dtsi | 6 ++++++
drivers/regulator/Kconfig | 2 +-
drivers/regulator/anatop-regulator.c | 25 +++++++++++++++----------
3 files changed, 22 insertions(+), 11 deletions(-)
diff --git a/arch/arm/boot/dts/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi
index db3fa15..da2bb71 100644
--- a/arch/arm/boot/dts/imx6q.dtsi
+++ b/arch/arm/boot/dts/imx6q.dtsi
@@ -395,6 +395,7 @@
anatop-min-bit-val = <4>;
anatop-min-voltage = <800000>;
anatop-max-voltage = <1375000>;
+ fsl,anatop = <&anatop>;
};
regulator-3p0@120 {
@@ -409,6 +410,7 @@
anatop-min-bit-val = <0>;
anatop-min-voltage = <2625000>;
anatop-max-voltage = <3400000>;
+ fsl,anatop = <&anatop>;
};
regulator-2p5@130 {
@@ -423,6 +425,7 @@
anatop-min-bit-val = <0>;
anatop-min-voltage = <2000000>;
anatop-max-voltage = <2750000>;
+ fsl,anatop = <&anatop>;
};
regulator-vddcore@140 {
@@ -437,6 +440,7 @@
anatop-min-bit-val = <1>;
anatop-min-voltage = <725000>;
anatop-max-voltage = <1450000>;
+ fsl,anatop = <&anatop>;
};
regulator-vddpu@140 {
@@ -451,6 +455,7 @@
anatop-min-bit-val = <1>;
anatop-min-voltage = <725000>;
anatop-max-voltage = <1450000>;
+ fsl,anatop = <&anatop>;
};
regulator-vddsoc@140 {
@@ -465,6 +470,7 @@
anatop-min-bit-val = <1>;
anatop-min-voltage = <725000>;
anatop-max-voltage = <1450000>;
+ fsl,anatop = <&anatop>;
};
};
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 4e932cc..2ae1d97 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -112,7 +112,7 @@ config REGULATOR_DA9052
config REGULATOR_ANATOP
tristate "Freescale i.MX on-chip ANATOP LDO regulators"
- depends on MFD_ANATOP
+ depends on MFD_SYSCON
help
Say y here to support Freescale i.MX on-chip ANATOP LDOs
regulators. It is recommended that this option be
diff --git a/drivers/regulator/anatop-regulator.c b/drivers/regulator/anatop-regulator.c
index ce0fe72..71586a7 100644
--- a/drivers/regulator/anatop-regulator.c
+++ b/drivers/regulator/anatop-regulator.c
@@ -21,19 +21,20 @@
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/module.h>
+#include <linux/mfd/syscon.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_address.h>
-#include <linux/mfd/anatop.h>
+#include <linux/regmap.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/of_regulator.h>
struct anatop_regulator {
const char *name;
u32 control_reg;
- struct anatop *mfd;
+ struct regmap *anatop;
int vol_bit_shift;
int vol_bit_width;
int min_bit_val;
@@ -43,7 +44,7 @@ struct anatop_regulator {
struct regulator_init_data *initdata;
};
-static int anatop_set_voltage_sel(struct regulator_dev *reg, unsigned selector)
+static int anatop_regmap_set_voltage_sel(struct regulator_dev *reg, unsigned selector)
{
struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
u32 val, mask;
@@ -56,12 +57,13 @@ static int anatop_set_voltage_sel(struct regulator_dev *reg, unsigned selector)
mask = ((1 << anatop_reg->vol_bit_width) - 1) <<
anatop_reg->vol_bit_shift;
val <<= anatop_reg->vol_bit_shift;
- anatop_write_reg(anatop_reg->mfd, anatop_reg->control_reg, val, mask);
+ regmap_update_bits(anatop_reg->anatop, anatop_reg->control_reg,
+ mask, val);
return 0;
}
-static int anatop_get_voltage_sel(struct regulator_dev *reg)
+static int anatop_regmap_get_voltage_sel(struct regulator_dev *reg)
{
struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
u32 val, mask;
@@ -69,7 +71,7 @@ static int anatop_get_voltage_sel(struct regulator_dev *reg)
if (!anatop_reg->control_reg)
return -ENOTSUPP;
- val = anatop_read_reg(anatop_reg->mfd, anatop_reg->control_reg);
+ regmap_read(anatop_reg->anatop, anatop_reg->control_reg, &val);
mask = ((1 << anatop_reg->vol_bit_width) - 1) <<
anatop_reg->vol_bit_shift;
val = (val & mask) >> anatop_reg->vol_bit_shift;
@@ -78,8 +80,8 @@ static int anatop_get_voltage_sel(struct regulator_dev *reg)
}
static struct regulator_ops anatop_rops = {
- .set_voltage_sel = anatop_set_voltage_sel,
- .get_voltage_sel = anatop_get_voltage_sel,
+ .set_voltage_sel = anatop_regmap_set_voltage_sel,
+ .get_voltage_sel = anatop_regmap_get_voltage_sel,
.list_voltage = regulator_list_voltage_linear,
.map_voltage = regulator_map_voltage_linear,
};
@@ -92,7 +94,6 @@ static int __devinit anatop_regulator_probe(struct platform_device *pdev)
struct regulator_dev *rdev;
struct anatop_regulator *sreg;
struct regulator_init_data *initdata;
- struct anatop *anatopmfd = dev_get_drvdata(pdev->dev.parent);
struct regulator_config config = { };
int ret = 0;
@@ -109,7 +110,11 @@ static int __devinit anatop_regulator_probe(struct platform_device *pdev)
rdesc->ops = &anatop_rops;
rdesc->type = REGULATOR_VOLTAGE;
rdesc->owner = THIS_MODULE;
- sreg->mfd = anatopmfd;
+
+ sreg->anatop = syscon_regmap_lookup_by_phandle(np, "fsl,anatop");
+ if (IS_ERR(sreg->anatop))
+ return PTR_ERR(sreg->anatop);
+
ret = of_property_read_u32(np, "anatop-reg-offset",
&sreg->control_reg);
if (ret) {
--
1.7.0.4
From: Dong Aisheng <[email protected]>
Originally the anatop regulator devices are populated by mfd anatop driver.
Since mfd anatop driver will be deleted later, we change to populate the
regulator devices by devicetree automatically.
This will cause some warning messages as follows during boot due to device
recreation: "vdd1p1: Failed to create debugfs directory"
But it does not break any function.
Later, we will remove mfd anatop driver which can get rid of this
error message.
Signed-off-by: Dong Aisheng <[email protected]>
---
arch/arm/boot/dts/imx6q.dtsi | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/arch/arm/boot/dts/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi
index da2bb71..0ebf853 100644
--- a/arch/arm/boot/dts/imx6q.dtsi
+++ b/arch/arm/boot/dts/imx6q.dtsi
@@ -379,7 +379,7 @@
};
anatop: anatop@020c8000 {
- compatible = "fsl,imx6q-anatop", "syscon";
+ compatible = "fsl,imx6q-anatop", "syscon", "simple-bus";
reg = <0x020c8000 0x1000>;
interrupts = <0 49 0x04 0 54 0x04 0 127 0x04>;
--
1.7.0.4
From: Dong Aisheng <[email protected]>
The anatop registers are accessed via syscon now, no one will use
mfd anatop driver anymore, remove it.
Signed-off-by: Dong Aisheng <[email protected]>
---
drivers/mfd/Kconfig | 8 ---
drivers/mfd/Makefile | 1 -
drivers/mfd/anatop-mfd.c | 124 --------------------------------------------
include/linux/mfd/anatop.h | 40 --------------
4 files changed, 0 insertions(+), 173 deletions(-)
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 4a6c48e..4fb3f49 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -985,14 +985,6 @@ config MFD_STA2X11
depends on STA2X11
select MFD_CORE
-config MFD_ANATOP
- bool "Support for Freescale i.MX on-chip ANATOP controller"
- depends on SOC_IMX6Q
- help
- Select this option to enable Freescale i.MX on-chip ANATOP
- MFD controller. This controller embeds regulator and
- thermal devices for Freescale i.MX platforms.
-
config MFD_SYSCON
bool "System Controller Register R/W Based on Regmap"
select REGMAP_MMIO
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 8384bc9..0f10a95 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -130,6 +130,5 @@ obj-$(CONFIG_MFD_INTEL_MSIC) += intel_msic.o
obj-$(CONFIG_MFD_PALMAS) += palmas.o
obj-$(CONFIG_MFD_RC5T583) += rc5t583.o rc5t583-irq.o
obj-$(CONFIG_MFD_SEC_CORE) += sec-core.o sec-irq.o
-obj-$(CONFIG_MFD_ANATOP) += anatop-mfd.o
obj-$(CONFIG_MFD_SYSCON) += syscon.o
obj-$(CONFIG_MFD_LM3533) += lm3533-core.o lm3533-ctrlbank.o
diff --git a/drivers/mfd/anatop-mfd.c b/drivers/mfd/anatop-mfd.c
deleted file mode 100644
index 5576e07..0000000
--- a/drivers/mfd/anatop-mfd.c
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Anatop MFD driver
- *
- * Copyright (C) 2012 Ying-Chun Liu (PaulLiu) <[email protected]>
- * Copyright (C) 2012 Linaro
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-
-#include <linux/io.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/of.h>
-#include <linux/of_platform.h>
-#include <linux/of_address.h>
-#include <linux/mfd/anatop.h>
-
-u32 anatop_read_reg(struct anatop *adata, u32 addr)
-{
- return readl(adata->ioreg + addr);
-}
-EXPORT_SYMBOL_GPL(anatop_read_reg);
-
-void anatop_write_reg(struct anatop *adata, u32 addr, u32 data, u32 mask)
-{
- u32 val;
-
- data &= mask;
-
- spin_lock(&adata->reglock);
- val = readl(adata->ioreg + addr);
- val &= ~mask;
- val |= data;
- writel(val, adata->ioreg + addr);
- spin_unlock(&adata->reglock);
-}
-EXPORT_SYMBOL_GPL(anatop_write_reg);
-
-static const struct of_device_id of_anatop_match[] = {
- { .compatible = "fsl,imx6q-anatop", },
- { },
-};
-
-static int __devinit of_anatop_probe(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
- struct device_node *np = dev->of_node;
- void *ioreg;
- struct anatop *drvdata;
-
- ioreg = of_iomap(np, 0);
- if (!ioreg)
- return -EADDRNOTAVAIL;
- drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
- if (!drvdata)
- return -ENOMEM;
- drvdata->ioreg = ioreg;
- spin_lock_init(&drvdata->reglock);
- platform_set_drvdata(pdev, drvdata);
- of_platform_populate(np, NULL, NULL, dev);
-
- return 0;
-}
-
-static int __devexit of_anatop_remove(struct platform_device *pdev)
-{
- struct anatop *drvdata;
- drvdata = platform_get_drvdata(pdev);
- iounmap(drvdata->ioreg);
-
- return 0;
-}
-
-static struct platform_driver anatop_of_driver = {
- .driver = {
- .name = "anatop-mfd",
- .owner = THIS_MODULE,
- .of_match_table = of_anatop_match,
- },
- .probe = of_anatop_probe,
- .remove = of_anatop_remove,
-};
-
-static int __init anatop_init(void)
-{
- return platform_driver_register(&anatop_of_driver);
-}
-postcore_initcall(anatop_init);
-
-static void __exit anatop_exit(void)
-{
- platform_driver_unregister(&anatop_of_driver);
-}
-module_exit(anatop_exit);
-
-MODULE_AUTHOR("Ying-Chun Liu (PaulLiu) <[email protected]>");
-MODULE_DESCRIPTION("ANATOP MFD driver");
-MODULE_LICENSE("GPL v2");
diff --git a/include/linux/mfd/anatop.h b/include/linux/mfd/anatop.h
deleted file mode 100644
index 7f92acf..0000000
--- a/include/linux/mfd/anatop.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * anatop.h - Anatop MFD driver
- *
- * Copyright (C) 2012 Ying-Chun Liu (PaulLiu) <[email protected]>
- * Copyright (C) 2012 Linaro
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef __LINUX_MFD_ANATOP_H
-#define __LINUX_MFD_ANATOP_H
-
-#include <linux/spinlock.h>
-
-/**
- * anatop - MFD data
- * @ioreg: ioremap register
- * @reglock: spinlock for register read/write
- */
-struct anatop {
- void *ioreg;
- spinlock_t reglock;
-};
-
-extern u32 anatop_read_reg(struct anatop *, u32);
-extern void anatop_write_reg(struct anatop *, u32, u32, u32);
-
-#endif /* __LINUX_MFD_ANATOP_H */
--
1.7.0.4
From: Dong Aisheng <[email protected]>
Using syscon to access anatop registers.
Signed-off-by: Dong Aisheng <[email protected]>
---
ChangeLog v1->v2:
* update to use generic regmap api
---
arch/arm/mach-imx/Kconfig | 2 +-
arch/arm/mach-imx/mach-imx6q.c | 43 ++++++++++++++++-----------------------
2 files changed, 19 insertions(+), 26 deletions(-)
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index afd542a..7bba253 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -839,7 +839,7 @@ config SOC_IMX6Q
select HAVE_IMX_MMDC
select HAVE_IMX_SRC
select HAVE_SMP
- select MFD_ANATOP
+ select MFD_SYSCON
select PINCTRL
select PINCTRL_IMX6Q
diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c
index 045b3f6..5de869a 100644
--- a/arch/arm/mach-imx/mach-imx6q.c
+++ b/arch/arm/mach-imx/mach-imx6q.c
@@ -24,8 +24,9 @@
#include <linux/of_platform.h>
#include <linux/pinctrl/machine.h>
#include <linux/phy.h>
+#include <linux/regmap.h>
#include <linux/micrel_phy.h>
-#include <linux/mfd/anatop.h>
+#include <linux/mfd/syscon.h>
#include <asm/cpuidle.h>
#include <asm/smp_twd.h>
#include <asm/hardware/cache-l2x0.h>
@@ -121,38 +122,30 @@ static void __init imx6q_sabrelite_init(void)
static void __init imx6q_usb_init(void)
{
struct device_node *np;
- struct platform_device *pdev = NULL;
- struct anatop *adata = NULL;
+ struct regmap *anatop;
np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-anatop");
- if (np)
- pdev = of_find_device_by_node(np);
- if (pdev)
- adata = platform_get_drvdata(pdev);
- if (!adata) {
- if (np)
- of_node_put(np);
- return;
- }
-
#define HW_ANADIG_USB1_CHRG_DETECT 0x000001b0
#define HW_ANADIG_USB2_CHRG_DETECT 0x00000210
#define BM_ANADIG_USB_CHRG_DETECT_EN_B 0x00100000
#define BM_ANADIG_USB_CHRG_DETECT_CHK_CHRG_B 0x00080000
- /*
- * The external charger detector needs to be disabled,
- * or the signal at DP will be poor
- */
- anatop_write_reg(adata, HW_ANADIG_USB1_CHRG_DETECT,
- BM_ANADIG_USB_CHRG_DETECT_EN_B
- | BM_ANADIG_USB_CHRG_DETECT_CHK_CHRG_B,
- ~0);
- anatop_write_reg(adata, HW_ANADIG_USB2_CHRG_DETECT,
- BM_ANADIG_USB_CHRG_DETECT_EN_B |
- BM_ANADIG_USB_CHRG_DETECT_CHK_CHRG_B,
- ~0);
+ anatop = syscon_regmap_lookup_by_compatible("fsl,imx6q-anatop");
+ if (!IS_ERR(anatop)) {
+ /*
+ * The external charger detector needs to be disabled,
+ * or the signal at DP will be poor
+ */
+ regmap_write(anatop, HW_ANADIG_USB1_CHRG_DETECT,
+ BM_ANADIG_USB_CHRG_DETECT_EN_B
+ | BM_ANADIG_USB_CHRG_DETECT_CHK_CHRG_B);
+ regmap_write(anatop, HW_ANADIG_USB2_CHRG_DETECT,
+ BM_ANADIG_USB_CHRG_DETECT_EN_B |
+ BM_ANADIG_USB_CHRG_DETECT_CHK_CHRG_B);
+ } else {
+ pr_warn("failed to find fsl,imx6q-anatop regmap\n");
+ }
of_node_put(np);
}
--
1.7.0.4
From: Dong Aisheng <[email protected]>
Add regmap based syscon driver.
This is usually used for access misc bits in registers which does not belong
to a specific module, for example, IMX IOMUXC GPR and ANATOP.
With this driver, client can use generic regmap API to access registers
which are registered into syscon.
Reviwed-by: Mark Brown <[email protected]>
Signed-off-by: Dong Aisheng <[email protected]>
---
ChangeLog:
v1->v2:
* provide a way of retrieving the regmap, suggested by Mark Brown.
* delete imx-syscon io accessors and using generic regmap API for client drivers.
* change to a more generic name for other SoCs to use.
---
.../devicetree/bindings/mfd/imx-syscon.txt | 11 ++
drivers/mfd/Kconfig | 7 +
drivers/mfd/Makefile | 1 +
drivers/mfd/syscon.c | 169 ++++++++++++++++++++
include/linux/mfd/syscon.h | 22 +++
5 files changed, 210 insertions(+), 0 deletions(-)
diff --git a/Documentation/devicetree/bindings/mfd/imx-syscon.txt b/Documentation/devicetree/bindings/mfd/imx-syscon.txt
new file mode 100644
index 0000000..c1a13b4
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/imx-syscon.txt
@@ -0,0 +1,11 @@
+* System Controller Registers R/W driver
+
+Required properties:
+- compatible: Should contain "syscon".
+- reg: the register range can be access from syscon
+
+Examples:
+gpr: iomuxc-gpr@020e0000 {
+ compatible = "fsl,imx6q-iomuxc", "syscon";
+ reg = <0x020e0000 0x38>;
+};
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index b1a1462..4a6c48e 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -993,6 +993,13 @@ config MFD_ANATOP
MFD controller. This controller embeds regulator and
thermal devices for Freescale i.MX platforms.
+config MFD_SYSCON
+ bool "System Controller Register R/W Based on Regmap"
+ select REGMAP_MMIO
+ help
+ Select this option to enable accessing system control registers
+ via regmap.
+
config MFD_PALMAS
bool "Support for the TI Palmas series chips"
select MFD_CORE
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 79dd22d..8384bc9 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -131,4 +131,5 @@ obj-$(CONFIG_MFD_PALMAS) += palmas.o
obj-$(CONFIG_MFD_RC5T583) += rc5t583.o rc5t583-irq.o
obj-$(CONFIG_MFD_SEC_CORE) += sec-core.o sec-irq.o
obj-$(CONFIG_MFD_ANATOP) += anatop-mfd.o
+obj-$(CONFIG_MFD_SYSCON) += syscon.o
obj-$(CONFIG_MFD_LM3533) += lm3533-core.o lm3533-ctrlbank.o
diff --git a/drivers/mfd/syscon.c b/drivers/mfd/syscon.c
new file mode 100644
index 0000000..da2464f
--- /dev/null
+++ b/drivers/mfd/syscon.c
@@ -0,0 +1,169 @@
+/*
+ * System Control Driver
+ *
+ * Copyright (C) 2012 Freescale Semiconductor, Inc.
+ * Copyright (C) 2012 Linaro Ltd.
+ *
+ * Author: Dong Aisheng <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+static struct platform_driver syscon_driver;
+
+struct syscon {
+ struct device *dev;
+ void __iomem *base;
+ struct regmap *regmap;
+};
+
+static int syscon_match(struct device *dev, void *data)
+{
+ struct syscon *syscon = dev_get_drvdata(dev);
+ struct device_node *dn = data;
+
+ return (syscon->dev->of_node == dn) ? 1 : 0;
+}
+
+static struct regmap *syscon_node_to_regmap(struct device_node *np)
+{
+ struct syscon *syscon;
+ struct device *dev;
+
+ dev = driver_find_device(&syscon_driver.driver, NULL, np,
+ syscon_match);
+ of_node_put(np);
+
+ if (!dev)
+ return ERR_PTR(-EPROBE_DEFER);
+
+ syscon = dev_get_drvdata(dev);
+
+ return syscon->regmap;
+}
+
+struct regmap *syscon_regmap_lookup_by_compatible(const char *s)
+{
+ struct device_node *syscon_np;
+
+ syscon_np = of_find_compatible_node(NULL, NULL, s);
+ if (!syscon_np)
+ return ERR_PTR(-ENODEV);
+
+ return syscon_node_to_regmap(syscon_np);
+}
+
+struct regmap *syscon_regmap_lookup_by_phandle(struct device_node *np,
+ const char *property)
+{
+ struct device_node *syscon_np;
+
+ syscon_np = of_parse_phandle(np, property, 0);
+ if (!syscon_np)
+ return ERR_PTR(-ENODEV);
+
+ return syscon_node_to_regmap(syscon_np);
+}
+
+static const struct of_device_id of_syscon_match[] = {
+ { .compatible = "syscon", },
+ { },
+};
+
+static struct regmap_config syscon_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+};
+
+static int __devinit syscon_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct syscon *syscon;
+ struct resource res;
+ int ret;
+
+ if (!np)
+ return -ENOENT;
+
+ syscon = devm_kzalloc(&pdev->dev, sizeof(struct syscon),
+ GFP_KERNEL);
+ if (!syscon)
+ return -ENOMEM;
+
+ syscon->base = of_iomap(np, 0);
+ if (!syscon->base)
+ return -EADDRNOTAVAIL;
+
+ ret = of_address_to_resource(np, 0, &res);
+ if (ret)
+ return ret;
+
+ syscon_regmap_config.max_register = res.end - res.start - 3;
+ syscon->regmap = devm_regmap_init_mmio(&pdev->dev, syscon->base,
+ &syscon_regmap_config);
+ if (IS_ERR(syscon->regmap)) {
+ dev_err(&pdev->dev, "regmap init failed\n");
+ return PTR_ERR(syscon->regmap);
+ }
+
+ regcache_cache_only(syscon->regmap, false);
+
+ syscon->dev = &pdev->dev;
+ platform_set_drvdata(pdev, syscon);
+
+ dev_info(dev, "syscon regmap start 0x%x end 0x%x registered\n",
+ res.start, res.end);
+
+ return 0;
+}
+
+static int __devexit syscon_remove(struct platform_device *pdev)
+{
+ struct syscon *syscon;
+
+ syscon = platform_get_drvdata(pdev);
+ iounmap(syscon->base);
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver syscon_driver = {
+ .driver = {
+ .name = "syscon",
+ .owner = THIS_MODULE,
+ .of_match_table = of_syscon_match,
+ },
+ .probe = syscon_probe,
+ .remove = syscon_remove,
+};
+
+static int __init syscon_init(void)
+{
+ return platform_driver_register(&syscon_driver);
+}
+postcore_initcall(syscon_init);
+
+static void __exit anatop_exit(void)
+{
+ platform_driver_unregister(&syscon_driver);
+}
+module_exit(anatop_exit);
+
+MODULE_AUTHOR("Dong Aisheng <[email protected]>");
+MODULE_DESCRIPTION("System Control driver");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/mfd/syscon.h b/include/linux/mfd/syscon.h
new file mode 100644
index 0000000..990d7cf
--- /dev/null
+++ b/include/linux/mfd/syscon.h
@@ -0,0 +1,22 @@
+/*
+ * System Control Driver
+ *
+ * Copyright (C) 2012 Freescale Semiconductor, Inc.
+ * Copyright (C) 2012 Linaro Ltd.
+ *
+ * Author: Dong Aisheng <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __LINUX_MFD_SYSCON_H__
+#define __LINUX_MFD_SYSCON_H__
+
+extern struct regmap *syscon_regmap_lookup_by_compatible(const char *s);
+extern struct regmap *syscon_regmap_lookup_by_phandle(
+ struct device_node *np,
+ const char *property);
+#endif /* __LINUX_MFD_SYSCON_H__ */
--
1.7.0.4
From: Dong Aisheng <[email protected]>
Include headfile for easy using.
Signed-off-by: Dong Aisheng <[email protected]>
---
arch/arm/boot/dts/imx6q.dtsi | 5 +
include/linux/fsl/imx6q-iomuxc-gpr.h | 319 ++++++++++++++++++++++++++++++++++
2 files changed, 324 insertions(+), 0 deletions(-)
diff --git a/arch/arm/boot/dts/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi
index fd57079..bea21bc 100644
--- a/arch/arm/boot/dts/imx6q.dtsi
+++ b/arch/arm/boot/dts/imx6q.dtsi
@@ -507,6 +507,11 @@
interrupts = <0 89 0x04 0 90 0x04>;
};
+ gpr: iomuxc-gpr@020e0000 {
+ compatible = "fsl,imx6q-iomuxc-gpr", "syscon";
+ reg = <0x020e0000 0x38>;
+ };
+
iomuxc@020e0000 {
compatible = "fsl,imx6q-iomuxc";
reg = <0x020e0000 0x4000>;
diff --git a/include/linux/fsl/imx6q-iomuxc-gpr.h b/include/linux/fsl/imx6q-iomuxc-gpr.h
new file mode 100644
index 0000000..2c44573
--- /dev/null
+++ b/include/linux/fsl/imx6q-iomuxc-gpr.h
@@ -0,0 +1,319 @@
+/*
+ * Copyright (C) 2012 Freescale Semiconductor, Inc.
+ *
+ * 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.
+ */
+
+#ifndef __LINUX_IMX6Q_IOMUXC_GPR_H
+#define __LINUX_IMX6Q_IOMUXC_GPR_H
+
+#include <linux/bitops.h>
+
+#define IOMUXC_GPR0 0x00
+#define IOMUXC_GPR1 0x04
+#define IOMUXC_GPR2 0x08
+#define IOMUXC_GPR3 0x0c
+#define IOMUXC_GPR4 0x10
+#define IOMUXC_GPR5 0x14
+#define IOMUXC_GPR6 0x18
+#define IOMUXC_GPR7 0x1c
+#define IOMUXC_GPR8 0x20
+#define IOMUXC_GPR9 0x24
+#define IOMUXC_GPR10 0x28
+#define IOMUXC_GPR11 0x2c
+#define IOMUXC_GPR12 0x30
+#define IOMUXC_GPR13 0x34
+
+#define IMX6Q_GPR0_CLOCK_8_MUX_SEL_MASK (0x3 << 30)
+#define IMX6Q_GPR0_CLOCK_8_MUX_SEL_AUDMUX_RXCLK_P7_MUXED (0x0 << 30)
+#define IMX6Q_GPR0_CLOCK_8_MUX_SEL_AUDMUX_RXCLK_P7 (0x1 << 30)
+#define IMX6Q_GPR0_CLOCK_8_MUX_SEL_SSI3_SSI_SRCK (0x2 << 30)
+#define IMX6Q_GPR0_CLOCK_8_MUX_SEL_SSI3_RX_BIT_CLK (0x3 << 30)
+#define IMX6Q_GPR0_CLOCK_0_MUX_SEL_MASK (0x3 << 28)
+#define IMX6Q_GPR0_CLOCK_0_MUX_SEL_ESAI1_IPP_IND_SCKR_MUXED (0x0 << 28)
+#define IMX6Q_GPR0_CLOCK_0_MUX_SEL_ESAI1_IPP_IND_SCKR (0x1 << 28)
+#define IMX6Q_GPR0_CLOCK_0_MUX_SEL_ESAI1_IPP_DO_SCKR (0x2 << 28)
+#define IMX6Q_GPR0_CLOCK_B_MUX_SEL_MASK (0x3 << 26)
+#define IMX6Q_GPR0_CLOCK_B_MUX_SEL_AUDMUX_TXCLK_P7_MUXED (0x0 << 26)
+#define IMX6Q_GPR0_CLOCK_B_MUX_SEL_AUDMUX_TXCLK_P7 (0x1 << 26)
+#define IMX6Q_GPR0_CLOCK_B_MUX_SEL_SSI3_SSI_STCK (0x2 << 26)
+#define IMX6Q_GPR0_CLOCK_B_MUX_SEL_SSI3_TX_BIT_CLK (0x3 << 26)
+#define IMX6Q_GPR0_CLOCK_3_MUX_SEL_MASK (0x3 << 24)
+#define IMX6Q_GPR0_CLOCK_3_MUX_SEL_AUDMUX_RXCLK_P7_MUXED (0x3 << 24)
+#define IMX6Q_GPR0_CLOCK_3_MUX_SEL_AUDMUX_RXCLK_P7 (0x3 << 24)
+#define IMX6Q_GPR0_CLOCK_3_MUX_SEL_SSI3_SSI_SRCK (0x3 << 24)
+#define IMX6Q_GPR0_CLOCK_3_MUX_SEL_SSI3_RX_BIT_CLK (0x3 << 24)
+#define IMX6Q_GPR0_CLOCK_A_MUX_SEL_MASK (0x3 << 22)
+#define IMX6Q_GPR0_CLOCK_A_MUX_SEL_AUDMUX_TXCLK_P2_MUXED (0x0 << 22)
+#define IMX6Q_GPR0_CLOCK_A_MUX_SEL_AUDMUX_TXCLK_P2 (0x1 << 22)
+#define IMX6Q_GPR0_CLOCK_A_MUX_SEL_SSI2_SSI_STCK (0x2 << 22)
+#define IMX6Q_GPR0_CLOCK_A_MUX_SEL_SSI2_TX_BIT_CLK (0x3 << 22)
+#define IMX6Q_GPR0_CLOCK_2_MUX_SEL_MASK (0x3 << 20)
+#define IMX6Q_GPR0_CLOCK_2_MUX_SEL_AUDMUX_RXCLK_P2_MUXED (0x0 << 20)
+#define IMX6Q_GPR0_CLOCK_2_MUX_SEL_AUDMUX_RXCLK_P2 (0x1 << 20)
+#define IMX6Q_GPR0_CLOCK_2_MUX_SEL_SSI2_SSI_SRCK (0x2 << 20)
+#define IMX6Q_GPR0_CLOCK_2_MUX_SEL_SSI2_RX_BIT_CLK (0x3 << 20)
+#define IMX6Q_GPR0_CLOCK_9_MUX_SEL_MASK (0x3 << 18)
+#define IMX6Q_GPR0_CLOCK_9_MUX_SEL_AUDMUX_TXCLK_P1_MUXED (0x0 << 18)
+#define IMX6Q_GPR0_CLOCK_9_MUX_SEL_AUDMUX_TXCLK_P1 (0x1 << 18)
+#define IMX6Q_GPR0_CLOCK_9_MUX_SEL_SSI1_SSI_STCK (0x2 << 18)
+#define IMX6Q_GPR0_CLOCK_9_MUX_SEL_SSI1_SSI_TX_BIT_CLK (0x3 << 18)
+#define IMX6Q_GPR0_CLOCK_1_MUX_SEL_MASK (0x3 << 16)
+#define IMX6Q_GPR0_CLOCK_1_MUX_SEL_AUDMUX_RXCLK_P1_MUXED (0x0 << 16)
+#define IMX6Q_GPR0_CLOCK_1_MUX_SEL_AUDMUX_RXCLK_P1 (0x1 << 16)
+#define IMX6Q_GPR0_CLOCK_1_MUX_SEL_SSI1_SSI_SRCK (0x2 << 16)
+#define IMX6Q_GPR0_CLOCK_1_MUX_SEL_SSI1_SSI_RX_BIT_CLK (0x3 << 16)
+#define IMX6Q_GPR0_TX_CLK2_MUX_SEL_MASK (0x3 << 14)
+#define IMX6Q_GPR0_TX_CLK2_MUX_SEL_ASRCK_CLK1 (0x0 << 14)
+#define IMX6Q_GPR0_TX_CLK2_MUX_SEL_ASRCK_CLK2 (0x1 << 14)
+#define IMX6Q_GPR0_TX_CLK2_MUX_SEL_ASRCK_CLK3 (0x2 << 14)
+#define IMX6Q_GPR0_DMAREQ_MUX_SEL7_MASK BIT(7)
+#define IMX6Q_GPR0_DMAREQ_MUX_SEL7_SPDIF 0x0
+#define IMX6Q_GPR0_DMAREQ_MUX_SEL7_IOMUX BIT(7)
+#define IMX6Q_GPR0_DMAREQ_MUX_SEL6_MASK BIT(6)
+#define IMX6Q_GPR0_DMAREQ_MUX_SEL6_ESAI 0x0
+#define IMX6Q_GPR0_DMAREQ_MUX_SEL6_I2C3 BIT(6)
+#define IMX6Q_GPR0_DMAREQ_MUX_SEL5_MASK BIT(5)
+#define IMX6Q_GPR0_DMAREQ_MUX_SEL5_ECSPI4 0x0
+#define IMX6Q_GPR0_DMAREQ_MUX_SEL5_EPIT2 BIT(5)
+#define IMX6Q_GPR0_DMAREQ_MUX_SEL4_MASK BIT(4)
+#define IMX6Q_GPR0_DMAREQ_MUX_SEL4_ECSPI4 0x0
+#define IMX6Q_GPR0_DMAREQ_MUX_SEL4_I2C1 BIT(4)
+#define IMX6Q_GPR0_DMAREQ_MUX_SEL3_MASK BIT(3)
+#define IMX6Q_GPR0_DMAREQ_MUX_SEL3_ECSPI2 0x0
+#define IMX6Q_GPR0_DMAREQ_MUX_SEL3_I2C1 BIT(3)
+#define IMX6Q_GPR0_DMAREQ_MUX_SEL2_MASK BIT(2)
+#define IMX6Q_GPR0_DMAREQ_MUX_SEL2_ECSPI1 0x0
+#define IMX6Q_GPR0_DMAREQ_MUX_SEL2_I2C2 BIT(2)
+#define IMX6Q_GPR0_DMAREQ_MUX_SEL1_MASK BIT(1)
+#define IMX6Q_GPR0_DMAREQ_MUX_SEL1_ECSPI1 0x0
+#define IMX6Q_GPR0_DMAREQ_MUX_SEL1_I2C3 BIT(1)
+#define IMX6Q_GPR0_DMAREQ_MUX_SEL0_MASK BIT(0)
+#define IMX6Q_GPR0_DMAREQ_MUX_SEL0_IPU1 0x0
+#define IMX6Q_GPR0_DMAREQ_MUX_SEL0_IOMUX BIT(0)
+
+#define IMX6Q_GPR1_PCIE_REQ_MASK (0x3 << 30)
+#define IMX6Q_GPR1_PCIE_EXIT_L1 BIT(28)
+#define IMX6Q_GPR1_PCIE_RDY_L23 BIT(27)
+#define IMX6Q_GPR1_PCIE_ENTER_L1 BIT(26)
+#define IMX6Q_GPR1_MIPI_COLOR_SW BIT(25)
+#define IMX6Q_GPR1_DPI_OFF BIT(24)
+#define IMX6Q_GPR1_EXC_MON_MASK BIT(22)
+#define IMX6Q_GPR1_EXC_MON_OKAY 0x0
+#define IMX6Q_GPR1_EXC_MON_SLVE BIT(22)
+#define IMX6Q_GPR1_MIPI_IPU2_SEL_MASK BIT(21)
+#define IMX6Q_GPR1_MIPI_IPU2_SEL_GASKET 0x0
+#define IMX6Q_GPR1_MIPI_IPU2_SEL_IOMUX BIT(21)
+#define IMX6Q_GPR1_MIPI_IPU1_MUX_MASK BIT(20)
+#define IMX6Q_GPR1_MIPI_IPU1_MUX_GASKET 0x0
+#define IMX6Q_GPR1_MIPI_IPU1_MUX_IOMUX BIT(20)
+#define IMX6Q_GPR1_MIPI_IPU2_MUX_MASK BIT(19)
+#define IMX6Q_GPR1_MIPI_IPU2_MUX_GASKET 0x0
+#define IMX6Q_GPR1_MIPI_IPU2_MUX_IOMUX BIT(19)
+#define IMX6Q_GPR1_PCIE_TEST_PD BIT(18)
+#define IMX6Q_GPR1_IPU_VPU_MUX_MASK BIT(17)
+#define IMX6Q_GPR1_IPU_VPU_MUX_IPU1 0x0
+#define IMX6Q_GPR1_IPU_VPU_MUX_IPU2 BIT(17)
+#define IMX6Q_GPR1_PCIE_REF_CLK_EN BIT(16)
+#define IMX6Q_GPR1_USB_EXP_MODE BIT(15)
+#define IMX6Q_GPR1_PCIE_INT BIT(14)
+#define IMX6Q_GPR1_USB_OTG_ID_SEL_MASK BIT(13)
+#define IMX6Q_GPR1_USB_OTG_ID_SEL_ENET_RX_ER 0x0
+#define IMX6Q_GPR1_USB_OTG_ID_SEL_GPIO_1 BIT(13)
+#define IMX6Q_GPR1_GINT BIT(12)
+#define IMX6Q_GPR1_ADDRS3_MASK (0x3 << 10)
+#define IMX6Q_GPR1_ADDRS3_32MB (0x0 << 10)
+#define IMX6Q_GPR1_ADDRS3_64MB (0x1 << 10)
+#define IMX6Q_GPR1_ADDRS3_128MB (0x2 << 10)
+#define IMX6Q_GPR1_ACT_CS3 BIT(9)
+#define IMX6Q_GPR1_ADDRS2_MASK (0x3 << 7)
+#define IMX6Q_GPR1_ACT_CS2 BIT(6)
+#define IMX6Q_GPR1_ADDRS1_MASK (0x3 << 4)
+#define IMX6Q_GPR1_ACT_CS1 BIT(3)
+#define IMX6Q_GPR1_ADDRS0_MASK (0x3 << 1)
+#define IMX6Q_GPR1_ACT_CS0 BIT(0)
+
+#define IMX6Q_GPR2_COUNTER_RESET_VAL_MASK (0x3 << 20)
+#define IMX6Q_GPR2_COUNTER_RESET_VAL_5 (0x0 << 20)
+#define IMX6Q_GPR2_COUNTER_RESET_VAL_3 (0x1 << 20)
+#define IMX6Q_GPR2_COUNTER_RESET_VAL_4 (0x2 << 20)
+#define IMX6Q_GPR2_COUNTER_RESET_VAL_6 (0x3 << 20)
+#define IMX6Q_GPR2_LVDS_CLK_SHIFT_MASK (0x7 << 16)
+#define IMX6Q_GPR2_LVDS_CLK_SHIFT_0 (0x0 << 16)
+#define IMX6Q_GPR2_LVDS_CLK_SHIFT_1 (0x1 << 16)
+#define IMX6Q_GPR2_LVDS_CLK_SHIFT_2 (0x2 << 16)
+#define IMX6Q_GPR2_LVDS_CLK_SHIFT_3 (0x3 << 16)
+#define IMX6Q_GPR2_LVDS_CLK_SHIFT_4 (0x4 << 16)
+#define IMX6Q_GPR2_LVDS_CLK_SHIFT_5 (0x5 << 16)
+#define IMX6Q_GPR2_LVDS_CLK_SHIFT_6 (0x6 << 16)
+#define IMX6Q_GPR2_LVDS_CLK_SHIFT_7 (0x7 << 16)
+#define IMX6Q_GPR2_BGREF_RRMODE_MASK BIT(15)
+#define IMX6Q_GPR2_BGREF_RRMODE_EXT_RESISTOR 0x0
+#define IMX6Q_GPR2_BGREF_RRMODE_INT_RESISTOR BIT(15)
+#define IMX6Q_GPR2_DI1_VS_POLARITY_MASK BIT(10)
+#define IMX6Q_GPR2_DI1_VS_POLARITY_ACTIVE_H 0x0
+#define IMX6Q_GPR2_DI1_VS_POLARITY_ACTIVE_L BIT(10)
+#define IMX6Q_GPR2_DI0_VS_POLARITY_MASK BIT(9)
+#define IMX6Q_GPR2_DI0_VS_POLARITY_ACTIVE_H 0x0
+#define IMX6Q_GPR2_DI0_VS_POLARITY_ACTIVE_L BIT(9)
+#define IMX6Q_GPR2_BIT_MAPPING_CH1_MASK BIT(8)
+#define IMX6Q_GPR2_BIT_MAPPING_CH1_SPWG 0x0
+#define IMX6Q_GPR2_BIT_MAPPING_CH1_JEIDA BIT(8)
+#define IMX6Q_GPR2_DATA_WIDTH_CH1_MASK BIT(7)
+#define IMX6Q_GPR2_DATA_WIDTH_CH1_18BIT 0x0
+#define IMX6Q_GPR2_DATA_WIDTH_CH1_24BIT BIT(7)
+#define IMX6Q_GPR2_BIT_MAPPING_CH0_MASK BIT(6)
+#define IMX6Q_GPR2_BIT_MAPPING_CH0_SPWG 0x0
+#define IMX6Q_GPR2_BIT_MAPPING_CH0_JEIDA BIT(6)
+#define IMX6Q_GPR2_DATA_WIDTH_CH0_MASK BIT(5)
+#define IMX6Q_GPR2_DATA_WIDTH_CH0_18BIT 0x0
+#define IMX6Q_GPR2_DATA_WIDTH_CH0_24BIT BIT(5)
+#define IMX6Q_GPR2_SPLIT_MODE_EN BIT(4)
+#define IMX6Q_GPR2_CH1_MODE_MASK (0x3 << 2)
+#define IMX6Q_GPR2_CH1_MODE_DISABLE (0x0 << 2)
+#define IMX6Q_GPR2_CH1_MODE_EN_ROUTE_DI0 (0x1 << 2)
+#define IMX6Q_GPR2_CH1_MODE_EN_ROUTE_DI1 (0x3 << 2)
+#define IMX6Q_GPR2_CH0_MODE_MASK (0x3 << 0)
+#define IMX6Q_GPR2_CH0_MODE_DISABLE (0x0 << 0)
+#define IMX6Q_GPR2_CH0_MODE_EN_ROUTE_DI0 (0x1 << 0)
+#define IMX6Q_GPR2_CH0_MODE_EN_ROUTE_DI1 (0x3 << 0)
+
+#define IMX6Q_GPR3_GPU_DBG_MASK (0x3 << 29)
+#define IMX6Q_GPR3_GPU_DBG_GPU3D (0x0 << 29)
+#define IMX6Q_GPR3_GPU_DBG_GPU2D (0x1 << 29)
+#define IMX6Q_GPR3_GPU_DBG_OPENVG (0x2 << 29)
+#define IMX6Q_GPR3_BCH_WR_CACHE_CTL BIT(28)
+#define IMX6Q_GPR3_BCH_RD_CACHE_CTL BIT(27)
+#define IMX6Q_GPR3_USDHCX_WR_CACHE_CTL BIT(26)
+#define IMX6Q_GPR3_USDHCX_RD_CACHE_CTL BIT(25)
+#define IMX6Q_GPR3_OCRAM_CTL_MASK (0xf << 21)
+#define IMX6Q_GPR3_OCRAM_STATUS_MASK (0xf << 17)
+#define IMX6Q_GPR3_CORE3_DBG_ACK_EN BIT(16)
+#define IMX6Q_GPR3_CORE2_DBG_ACK_EN BIT(15)
+#define IMX6Q_GPR3_CORE1_DBG_ACK_EN BIT(14)
+#define IMX6Q_GPR3_CORE0_DBG_ACK_EN BIT(13)
+#define IMX6Q_GPR3_TZASC2_BOOT_LOCK BIT(12)
+#define IMX6Q_GPR3_TZASC1_BOOT_LOCK BIT(11)
+#define IMX6Q_GPR3_IPU_DIAG_MASK BIT(10)
+#define IMX6Q_GPR3_LVDS1_MUX_CTL_MASK (0x3 << 8)
+#define IMX6Q_GPR3_LVDS1_MUX_CTL_IPU1_DI0 (0x0 << 8)
+#define IMX6Q_GPR3_LVDS1_MUX_CTL_IPU1_DI1 (0x1 << 8)
+#define IMX6Q_GPR3_LVDS1_MUX_CTL_IPU2_DI0 (0x2 << 8)
+#define IMX6Q_GPR3_LVDS1_MUX_CTL_IPU2_DI1 (0x3 << 8)
+#define IMX6Q_GPR3_LVDS0_MUX_CTL_MASK (0x3 << 6)
+#define IMX6Q_GPR3_LVDS0_MUX_CTL_IPU1_DI0 (0x0 << 6)
+#define IMX6Q_GPR3_LVDS0_MUX_CTL_IPU1_DI1 (0x1 << 6)
+#define IMX6Q_GPR3_LVDS0_MUX_CTL_IPU2_DI0 (0x2 << 6)
+#define IMX6Q_GPR3_LVDS0_MUX_CTL_IPU2_DI1 (0x3 << 6)
+#define IMX6Q_GPR3_MIPI_MUX_CTL_MASK (0x3 << 4)
+#define IMX6Q_GPR3_MIPI_MUX_CTL_IPU1_DI0 (0x0 << 4)
+#define IMX6Q_GPR3_MIPI_MUX_CTL_IPU1_DI1 (0x1 << 4)
+#define IMX6Q_GPR3_MIPI_MUX_CTL_IPU2_DI0 (0x2 << 4)
+#define IMX6Q_GPR3_MIPI_MUX_CTL_IPU2_DI1 (0x3 << 4)
+#define IMX6Q_GPR3_HDMI_MUX_CTL_MASK (0x3 << 2)
+#define IMX6Q_GPR3_HDMI_MUX_CTL_IPU1_DI0 (0x0 << 2)
+#define IMX6Q_GPR3_HDMI_MUX_CTL_IPU1_DI1 (0x1 << 2)
+#define IMX6Q_GPR3_HDMI_MUX_CTL_IPU2_DI0 (0x2 << 2)
+#define IMX6Q_GPR3_HDMI_MUX_CTL_IPU2_DI1 (0x3 << 2)
+
+#define IMX6Q_GPR4_VDOA_WR_CACHE_SEL BIT(31)
+#define IMX6Q_GPR4_VDOA_RD_CACHE_SEL BIT(30)
+#define IMX6Q_GPR4_VDOA_WR_CACHE_VAL BIT(29)
+#define IMX6Q_GPR4_VDOA_RD_CACHE_VAL BIT(28)
+#define IMX6Q_GPR4_PCIE_WR_CACHE_SEL BIT(27)
+#define IMX6Q_GPR4_PCIE_RD_CACHE_SEL BIT(26)
+#define IMX6Q_GPR4_PCIE_WR_CACHE_VAL BIT(25)
+#define IMX6Q_GPR4_PCIE_RD_CACHE_VAL BIT(24)
+#define IMX6Q_GPR4_SDMA_STOP_ACK BIT(19)
+#define IMX6Q_GPR4_CAN2_STOP_ACK BIT(18)
+#define IMX6Q_GPR4_CAN1_STOP_ACK BIT(17)
+#define IMX6Q_GPR4_ENET_STOP_ACK BIT(16)
+#define IMX6Q_GPR4_SOC_VERSION_MASK (0xff << 8)
+#define IMX6Q_GPR4_SOC_VERSION_OFF 0x8
+#define IMX6Q_GPR4_VPU_WR_CACHE_SEL BIT(7)
+#define IMX6Q_GPR4_VPU_RD_CACHE_SEL BIT(6)
+#define IMX6Q_GPR4_VPU_P_WR_CACHE_VAL BIT(3)
+#define IMX6Q_GPR4_VPU_P_RD_CACHE_VAL_MASK BIT(2)
+#define IMX6Q_GPR4_IPU_WR_CACHE_CTL BIT(1)
+#define IMX6Q_GPR4_IPU_RD_CACHE_CTL BIT(0)
+
+#define IMX6Q_GPR5_L2_CLK_STOP BIT(8)
+
+#define IMX6Q_GPR9_TZASC2_BYP BIT(1)
+#define IMX6Q_GPR9_TZASC1_BYP BIT(0)
+
+#define IMX6Q_GPR10_LOCK_DBG_EN BIT(29)
+#define IMX6Q_GPR10_LOCK_DBG_CLK_EN BIT(28)
+#define IMX6Q_GPR10_LOCK_SEC_ERR_RESP BIT(27)
+#define IMX6Q_GPR10_LOCK_OCRAM_TZ_ADDR (0x3f << 21)
+#define IMX6Q_GPR10_LOCK_OCRAM_TZ_EN BIT(20)
+#define IMX6Q_GPR10_LOCK_DCIC2_MUX_MASK (0x3 << 18)
+#define IMX6Q_GPR10_LOCK_DCIC1_MUX_MASK (0x3 << 16)
+#define IMX6Q_GPR10_DBG_EN BIT(13)
+#define IMX6Q_GPR10_DBG_CLK_EN BIT(12)
+#define IMX6Q_GPR10_SEC_ERR_RESP_MASK BIT(11)
+#define IMX6Q_GPR10_SEC_ERR_RESP_OKEY 0x0
+#define IMX6Q_GPR10_SEC_ERR_RESP_SLVE BIT(11)
+#define IMX6Q_GPR10_OCRAM_TZ_ADDR_MASK (0x3f << 5)
+#define IMX6Q_GPR10_OCRAM_TZ_EN_MASK BIT(4)
+#define IMX6Q_GPR10_DCIC2_MUX_CTL_MASK (0x3 << 2)
+#define IMX6Q_GPR10_DCIC2_MUX_CTL_IPU1_DI0 (0x0 << 2)
+#define IMX6Q_GPR10_DCIC2_MUX_CTL_IPU1_DI1 (0x1 << 2)
+#define IMX6Q_GPR10_DCIC2_MUX_CTL_IPU2_DI0 (0x2 << 2)
+#define IMX6Q_GPR10_DCIC2_MUX_CTL_IPU2_DI1 (0x3 << 2)
+#define IMX6Q_GPR10_DCIC1_MUX_CTL_MASK (0x3 << 0)
+#define IMX6Q_GPR10_DCIC1_MUX_CTL_IPU1_DI0 (0x0 << 0)
+#define IMX6Q_GPR10_DCIC1_MUX_CTL_IPU1_DI1 (0x1 << 0)
+#define IMX6Q_GPR10_DCIC1_MUX_CTL_IPU2_DI0 (0x2 << 0)
+#define IMX6Q_GPR10_DCIC1_MUX_CTL_IPU2_DI1 (0x3 << 0)
+
+#define IMX6Q_GPR12_ARMP_IPG_CLK_EN BIT(27)
+#define IMX6Q_GPR12_ARMP_AHB_CLK_EN BIT(26)
+#define IMX6Q_GPR12_ARMP_ATB_CLK_EN BIT(25)
+#define IMX6Q_GPR12_ARMP_APB_CLK_EN BIT(24)
+#define IMX6Q_GPR12_PCIE_CTL_2 BIT(10)
+
+#define IMX6Q_GPR13_SDMA_STOP_REQ BIT(30)
+#define IMX6Q_GPR13_CAN2_STOP_REQ BIT(29)
+#define IMX6Q_GPR13_CAN1_STOP_REQ BIT(28)
+#define IMX6Q_GPR13_ENET_STOP_REQ BIT(27)
+#define IMX6Q_GPR13_SATA_PHY_8_MASK (0x7 << 24)
+#define IMX6Q_GPR13_SATA_PHY_8_0_5_DB (0x0 << 24)
+#define IMX6Q_GPR13_SATA_PHY_8_1_0_DB (0x1 << 24)
+#define IMX6Q_GPR13_SATA_PHY_8_1_5_DB (0x2 << 24)
+#define IMX6Q_GPR13_SATA_PHY_8_2_0_DB (0x3 << 24)
+#define IMX6Q_GPR13_SATA_PHY_8_2_5_DB (0x4 << 24)
+#define IMX6Q_GPR13_SATA_PHY_8_3_0_DB (0x5 << 24)
+#define IMX6Q_GPR13_SATA_PHY_8_3_5_DB (0x6 << 24)
+#define IMX6Q_GPR13_SATA_PHY_8_4_0_DB (0x7 << 24)
+#define IMX6Q_GPR13_SATA_PHY_7_MASK (0x1f << 19)
+#define IMX6Q_GPR13_SATA_PHY_7_SATA1I (0x10 << 19)
+#define IMX6Q_GPR13_SATA_PHY_7_SATA1M (0x10 << 19)
+#define IMX6Q_GPR13_SATA_PHY_7_SATA1X (0x1a << 19)
+#define IMX6Q_GPR13_SATA_PHY_7_SATA2I (0x12 << 19)
+#define IMX6Q_GPR13_SATA_PHY_7_SATA2M (0x12 << 19)
+#define IMX6Q_GPR13_SATA_PHY_7_SATA2X (0x1a << 19)
+#define IMX6Q_GPR13_SATA_PHY_6_MASK (0x7 << 16)
+#define IMX6Q_GPR13_SATA_SPEED_MASK BIT(15)
+#define IMX6Q_GPR13_SATA_SPEED_1P5G 0x0
+#define IMX6Q_GPR13_SATA_SPEED_3P0G BIT(15)
+#define IMX6Q_GPR13_SATA_PHY_5 BIT(14)
+#define IMX6Q_GPR13_SATA_PHY_4_MASK (0x7 << 11)
+#define IMX6Q_GPR13_SATA_PHY_4_16_16 (0x0 << 11)
+#define IMX6Q_GPR13_SATA_PHY_4_14_16 (0x1 << 11)
+#define IMX6Q_GPR13_SATA_PHY_4_12_16 (0x2 << 11)
+#define IMX6Q_GPR13_SATA_PHY_4_10_16 (0x3 << 11)
+#define IMX6Q_GPR13_SATA_PHY_4_9_16 (0x4 << 11)
+#define IMX6Q_GPR13_SATA_PHY_4_8_16 (0x5 << 11)
+#define IMX6Q_GPR13_SATA_PHY_3_MASK (0xf << 7)
+#define IMX6Q_GPR13_SATA_PHY_3_OFF 0x7
+#define IMX6Q_GPR13_SATA_PHY_2_MASK (0x1f << 2)
+#define IMX6Q_GPR13_SATA_PHY_2_OFF 0x2
+#define IMX6Q_GPR13_SATA_PHY_1_MASK (0x3 << 0)
+#define IMX6Q_GPR13_SATA_PHY_1_FAST (0x0 << 0)
+#define IMX6Q_GPR13_SATA_PHY_1_MED (0x1 << 0)
+#define IMX6Q_GPR13_SATA_PHY_1_SLOW (0x2 << 0)
+
+#endif /* !__LINUX_IMX6Q_IOMUXC_GPR_H */
--
1.7.0.4
On Mon, Aug 27, 2012 at 03:24:39PM +0800, Dong Aisheng wrote:
> From: Dong Aisheng <[email protected]>
>
> Add regmap based syscon driver.
> This is usually used for access misc bits in registers which does not belong
> to a specific module, for example, IMX IOMUXC GPR and ANATOP.
> With this driver, client can use generic regmap API to access registers
> which are registered into syscon.
>
> Reviwed-by: Mark Brown <[email protected]>
> Signed-off-by: Dong Aisheng <[email protected]>
> ---
> ChangeLog:
> v1->v2:
> * provide a way of retrieving the regmap, suggested by Mark Brown.
> * delete imx-syscon io accessors and using generic regmap API for client drivers.
> * change to a more generic name for other SoCs to use.
> ---
> .../devicetree/bindings/mfd/imx-syscon.txt | 11 ++
So, this file should be renamed as well.
> drivers/mfd/Kconfig | 7 +
> drivers/mfd/Makefile | 1 +
> drivers/mfd/syscon.c | 169 ++++++++++++++++++++
> include/linux/mfd/syscon.h | 22 +++
> 5 files changed, 210 insertions(+), 0 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/mfd/imx-syscon.txt b/Documentation/devicetree/bindings/mfd/imx-syscon.txt
> new file mode 100644
> index 0000000..c1a13b4
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mfd/imx-syscon.txt
> @@ -0,0 +1,11 @@
> +* System Controller Registers R/W driver
> +
> +Required properties:
> +- compatible: Should contain "syscon".
> +- reg: the register range can be access from syscon
> +
> +Examples:
> +gpr: iomuxc-gpr@020e0000 {
> + compatible = "fsl,imx6q-iomuxc", "syscon";
> + reg = <0x020e0000 0x38>;
> +};
> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> index b1a1462..4a6c48e 100644
> --- a/drivers/mfd/Kconfig
> +++ b/drivers/mfd/Kconfig
> @@ -993,6 +993,13 @@ config MFD_ANATOP
> MFD controller. This controller embeds regulator and
> thermal devices for Freescale i.MX platforms.
>
> +config MFD_SYSCON
> + bool "System Controller Register R/W Based on Regmap"
> + select REGMAP_MMIO
> + help
> + Select this option to enable accessing system control registers
> + via regmap.
> +
> config MFD_PALMAS
> bool "Support for the TI Palmas series chips"
> select MFD_CORE
> diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
> index 79dd22d..8384bc9 100644
> --- a/drivers/mfd/Makefile
> +++ b/drivers/mfd/Makefile
> @@ -131,4 +131,5 @@ obj-$(CONFIG_MFD_PALMAS) += palmas.o
> obj-$(CONFIG_MFD_RC5T583) += rc5t583.o rc5t583-irq.o
> obj-$(CONFIG_MFD_SEC_CORE) += sec-core.o sec-irq.o
> obj-$(CONFIG_MFD_ANATOP) += anatop-mfd.o
> +obj-$(CONFIG_MFD_SYSCON) += syscon.o
> obj-$(CONFIG_MFD_LM3533) += lm3533-core.o lm3533-ctrlbank.o
> diff --git a/drivers/mfd/syscon.c b/drivers/mfd/syscon.c
> new file mode 100644
> index 0000000..da2464f
> --- /dev/null
> +++ b/drivers/mfd/syscon.c
> @@ -0,0 +1,169 @@
> +/*
> + * System Control Driver
> + *
> + * Copyright (C) 2012 Freescale Semiconductor, Inc.
> + * Copyright (C) 2012 Linaro Ltd.
> + *
> + * Author: Dong Aisheng <[email protected]>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + */
> +
> +#include <linux/err.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/of_platform.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +
> +static struct platform_driver syscon_driver;
> +
> +struct syscon {
> + struct device *dev;
> + void __iomem *base;
> + struct regmap *regmap;
> +};
> +
> +static int syscon_match(struct device *dev, void *data)
> +{
> + struct syscon *syscon = dev_get_drvdata(dev);
> + struct device_node *dn = data;
> +
> + return (syscon->dev->of_node == dn) ? 1 : 0;
> +}
> +
> +static struct regmap *syscon_node_to_regmap(struct device_node *np)
> +{
> + struct syscon *syscon;
> + struct device *dev;
> +
> + dev = driver_find_device(&syscon_driver.driver, NULL, np,
> + syscon_match);
> + of_node_put(np);
> +
> + if (!dev)
> + return ERR_PTR(-EPROBE_DEFER);
> +
> + syscon = dev_get_drvdata(dev);
> +
> + return syscon->regmap;
> +}
> +
> +struct regmap *syscon_regmap_lookup_by_compatible(const char *s)
> +{
> + struct device_node *syscon_np;
> +
> + syscon_np = of_find_compatible_node(NULL, NULL, s);
> + if (!syscon_np)
> + return ERR_PTR(-ENODEV);
> +
> + return syscon_node_to_regmap(syscon_np);
> +}
> +
> +struct regmap *syscon_regmap_lookup_by_phandle(struct device_node *np,
> + const char *property)
> +{
> + struct device_node *syscon_np;
> +
> + syscon_np = of_parse_phandle(np, property, 0);
> + if (!syscon_np)
> + return ERR_PTR(-ENODEV);
> +
> + return syscon_node_to_regmap(syscon_np);
> +}
The above two APIs are all about finding the device_node for syscon,
and can be done by clients in whatever way that is easy for them.
Then we can save these APIs and export syscon_node_to_regmap directly.
> +
> +static const struct of_device_id of_syscon_match[] = {
> + { .compatible = "syscon", },
> + { },
> +};
> +
> +static struct regmap_config syscon_regmap_config = {
> + .reg_bits = 32,
> + .val_bits = 32,
> + .reg_stride = 4,
> +};
> +
> +static int __devinit syscon_probe(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> + struct device_node *np = dev->of_node;
> + struct syscon *syscon;
> + struct resource res;
> + int ret;
> +
> + if (!np)
> + return -ENOENT;
> +
> + syscon = devm_kzalloc(&pdev->dev, sizeof(struct syscon),
> + GFP_KERNEL);
> + if (!syscon)
> + return -ENOMEM;
> +
> + syscon->base = of_iomap(np, 0);
> + if (!syscon->base)
> + return -EADDRNOTAVAIL;
> +
> + ret = of_address_to_resource(np, 0, &res);
> + if (ret)
> + return ret;
> +
> + syscon_regmap_config.max_register = res.end - res.start - 3;
> + syscon->regmap = devm_regmap_init_mmio(&pdev->dev, syscon->base,
> + &syscon_regmap_config);
> + if (IS_ERR(syscon->regmap)) {
> + dev_err(&pdev->dev, "regmap init failed\n");
> + return PTR_ERR(syscon->regmap);
> + }
> +
> + regcache_cache_only(syscon->regmap, false);
> +
> + syscon->dev = &pdev->dev;
> + platform_set_drvdata(pdev, syscon);
> +
> + dev_info(dev, "syscon regmap start 0x%x end 0x%x registered\n",
> + res.start, res.end);
> +
> + return 0;
> +}
> +
> +static int __devexit syscon_remove(struct platform_device *pdev)
> +{
> + struct syscon *syscon;
> +
> + syscon = platform_get_drvdata(pdev);
> + iounmap(syscon->base);
> + platform_set_drvdata(pdev, NULL);
> +
> + return 0;
> +}
> +
> +static struct platform_driver syscon_driver = {
> + .driver = {
> + .name = "syscon",
> + .owner = THIS_MODULE,
> + .of_match_table = of_syscon_match,
> + },
> + .probe = syscon_probe,
> + .remove = syscon_remove,
> +};
> +
> +static int __init syscon_init(void)
> +{
> + return platform_driver_register(&syscon_driver);
> +}
> +postcore_initcall(syscon_init);
> +
> +static void __exit anatop_exit(void)
s/anatop_exit/syscon_exit
> +{
> + platform_driver_unregister(&syscon_driver);
> +}
> +module_exit(anatop_exit);
Ditto.
Regards,
Shawn
> +
> +MODULE_AUTHOR("Dong Aisheng <[email protected]>");
> +MODULE_DESCRIPTION("System Control driver");
> +MODULE_LICENSE("GPL v2");
> diff --git a/include/linux/mfd/syscon.h b/include/linux/mfd/syscon.h
> new file mode 100644
> index 0000000..990d7cf
> --- /dev/null
> +++ b/include/linux/mfd/syscon.h
> @@ -0,0 +1,22 @@
> +/*
> + * System Control Driver
> + *
> + * Copyright (C) 2012 Freescale Semiconductor, Inc.
> + * Copyright (C) 2012 Linaro Ltd.
> + *
> + * Author: Dong Aisheng <[email protected]>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + */
> +
> +#ifndef __LINUX_MFD_SYSCON_H__
> +#define __LINUX_MFD_SYSCON_H__
> +
> +extern struct regmap *syscon_regmap_lookup_by_compatible(const char *s);
> +extern struct regmap *syscon_regmap_lookup_by_phandle(
> + struct device_node *np,
> + const char *property);
> +#endif /* __LINUX_MFD_SYSCON_H__ */
> --
> 1.7.0.4
>
>
On Mon, Aug 27, 2012 at 03:24:42PM +0800, Dong Aisheng wrote:
> From: Dong Aisheng <[email protected]>
>
> Using syscon to access anatop register.
>
> Acked-by: Mark Brown <[email protected]>
> Signed-off-by: Dong Aisheng <[email protected]>
> ---
> ChangeLog v1-v2:
> * update to use generic regmap api
> ---
> arch/arm/boot/dts/imx6q.dtsi | 6 ++++++
> drivers/regulator/Kconfig | 2 +-
> drivers/regulator/anatop-regulator.c | 25 +++++++++++++++----------
> 3 files changed, 22 insertions(+), 11 deletions(-)
>
> diff --git a/arch/arm/boot/dts/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi
> index db3fa15..da2bb71 100644
> --- a/arch/arm/boot/dts/imx6q.dtsi
> +++ b/arch/arm/boot/dts/imx6q.dtsi
> @@ -395,6 +395,7 @@
> anatop-min-bit-val = <4>;
> anatop-min-voltage = <800000>;
> anatop-max-voltage = <1375000>;
> + fsl,anatop = <&anatop>;
> };
>
> regulator-3p0@120 {
> @@ -409,6 +410,7 @@
> anatop-min-bit-val = <0>;
> anatop-min-voltage = <2625000>;
> anatop-max-voltage = <3400000>;
> + fsl,anatop = <&anatop>;
> };
>
> regulator-2p5@130 {
> @@ -423,6 +425,7 @@
> anatop-min-bit-val = <0>;
> anatop-min-voltage = <2000000>;
> anatop-max-voltage = <2750000>;
> + fsl,anatop = <&anatop>;
> };
>
> regulator-vddcore@140 {
> @@ -437,6 +440,7 @@
> anatop-min-bit-val = <1>;
> anatop-min-voltage = <725000>;
> anatop-max-voltage = <1450000>;
> + fsl,anatop = <&anatop>;
> };
>
> regulator-vddpu@140 {
> @@ -451,6 +455,7 @@
> anatop-min-bit-val = <1>;
> anatop-min-voltage = <725000>;
> anatop-max-voltage = <1450000>;
> + fsl,anatop = <&anatop>;
> };
>
> regulator-vddsoc@140 {
> @@ -465,6 +470,7 @@
> anatop-min-bit-val = <1>;
> anatop-min-voltage = <725000>;
> anatop-max-voltage = <1450000>;
> + fsl,anatop = <&anatop>;
> };
> };
>
> diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
> index 4e932cc..2ae1d97 100644
> --- a/drivers/regulator/Kconfig
> +++ b/drivers/regulator/Kconfig
> @@ -112,7 +112,7 @@ config REGULATOR_DA9052
>
> config REGULATOR_ANATOP
> tristate "Freescale i.MX on-chip ANATOP LDO regulators"
> - depends on MFD_ANATOP
> + depends on MFD_SYSCON
> help
> Say y here to support Freescale i.MX on-chip ANATOP LDOs
> regulators. It is recommended that this option be
> diff --git a/drivers/regulator/anatop-regulator.c b/drivers/regulator/anatop-regulator.c
> index ce0fe72..71586a7 100644
> --- a/drivers/regulator/anatop-regulator.c
> +++ b/drivers/regulator/anatop-regulator.c
> @@ -21,19 +21,20 @@
> #include <linux/slab.h>
> #include <linux/device.h>
> #include <linux/module.h>
> +#include <linux/mfd/syscon.h>
> #include <linux/err.h>
> #include <linux/io.h>
> #include <linux/platform_device.h>
> #include <linux/of.h>
> #include <linux/of_address.h>
> -#include <linux/mfd/anatop.h>
> +#include <linux/regmap.h>
> #include <linux/regulator/driver.h>
> #include <linux/regulator/of_regulator.h>
>
> struct anatop_regulator {
> const char *name;
> u32 control_reg;
> - struct anatop *mfd;
> + struct regmap *anatop;
> int vol_bit_shift;
> int vol_bit_width;
> int min_bit_val;
> @@ -43,7 +44,7 @@ struct anatop_regulator {
> struct regulator_init_data *initdata;
> };
>
> -static int anatop_set_voltage_sel(struct regulator_dev *reg, unsigned selector)
> +static int anatop_regmap_set_voltage_sel(struct regulator_dev *reg, unsigned selector)
> {
> struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
> u32 val, mask;
> @@ -56,12 +57,13 @@ static int anatop_set_voltage_sel(struct regulator_dev *reg, unsigned selector)
> mask = ((1 << anatop_reg->vol_bit_width) - 1) <<
> anatop_reg->vol_bit_shift;
> val <<= anatop_reg->vol_bit_shift;
> - anatop_write_reg(anatop_reg->mfd, anatop_reg->control_reg, val, mask);
> + regmap_update_bits(anatop_reg->anatop, anatop_reg->control_reg,
> + mask, val);
>
> return 0;
> }
>
> -static int anatop_get_voltage_sel(struct regulator_dev *reg)
> +static int anatop_regmap_get_voltage_sel(struct regulator_dev *reg)
> {
> struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
> u32 val, mask;
> @@ -69,7 +71,7 @@ static int anatop_get_voltage_sel(struct regulator_dev *reg)
> if (!anatop_reg->control_reg)
> return -ENOTSUPP;
>
> - val = anatop_read_reg(anatop_reg->mfd, anatop_reg->control_reg);
> + regmap_read(anatop_reg->anatop, anatop_reg->control_reg, &val);
> mask = ((1 << anatop_reg->vol_bit_width) - 1) <<
> anatop_reg->vol_bit_shift;
> val = (val & mask) >> anatop_reg->vol_bit_shift;
> @@ -78,8 +80,8 @@ static int anatop_get_voltage_sel(struct regulator_dev *reg)
> }
>
> static struct regulator_ops anatop_rops = {
> - .set_voltage_sel = anatop_set_voltage_sel,
> - .get_voltage_sel = anatop_get_voltage_sel,
> + .set_voltage_sel = anatop_regmap_set_voltage_sel,
> + .get_voltage_sel = anatop_regmap_get_voltage_sel,
> .list_voltage = regulator_list_voltage_linear,
> .map_voltage = regulator_map_voltage_linear,
> };
> @@ -92,7 +94,6 @@ static int __devinit anatop_regulator_probe(struct platform_device *pdev)
> struct regulator_dev *rdev;
> struct anatop_regulator *sreg;
> struct regulator_init_data *initdata;
> - struct anatop *anatopmfd = dev_get_drvdata(pdev->dev.parent);
> struct regulator_config config = { };
> int ret = 0;
>
> @@ -109,7 +110,11 @@ static int __devinit anatop_regulator_probe(struct platform_device *pdev)
> rdesc->ops = &anatop_rops;
> rdesc->type = REGULATOR_VOLTAGE;
> rdesc->owner = THIS_MODULE;
> - sreg->mfd = anatopmfd;
> +
> + sreg->anatop = syscon_regmap_lookup_by_phandle(np, "fsl,anatop");
> + if (IS_ERR(sreg->anatop))
> + return PTR_ERR(sreg->anatop);
> +
All the anatop regulators are child nodes of anatop. It looks a little
odd to use phandle there. of_get_parent should just works.
> ret = of_property_read_u32(np, "anatop-reg-offset",
> &sreg->control_reg);
> if (ret) {
> --
> 1.7.0.4
>
>
--
Regards,
Shawn
On Tue, Aug 28, 2012 at 06:08:32AM +0800, Shawn Guo wrote:
> On Mon, Aug 27, 2012 at 03:24:39PM +0800, Dong Aisheng wrote:
> > From: Dong Aisheng <[email protected]>
> >
> > Add regmap based syscon driver.
> > This is usually used for access misc bits in registers which does not belong
> > to a specific module, for example, IMX IOMUXC GPR and ANATOP.
> > With this driver, client can use generic regmap API to access registers
> > which are registered into syscon.
> >
> > Reviwed-by: Mark Brown <[email protected]>
> > Signed-off-by: Dong Aisheng <[email protected]>
> > ---
> > ChangeLog:
> > v1->v2:
> > * provide a way of retrieving the regmap, suggested by Mark Brown.
> > * delete imx-syscon io accessors and using generic regmap API for client drivers.
> > * change to a more generic name for other SoCs to use.
> > ---
> > .../devicetree/bindings/mfd/imx-syscon.txt | 11 ++
>
> So, this file should be renamed as well.
>
Correct.
I missed it, thanks for reminder.
> > drivers/mfd/Kconfig | 7 +
> > drivers/mfd/Makefile | 1 +
> > drivers/mfd/syscon.c | 169 ++++++++++++++++++++
> > include/linux/mfd/syscon.h | 22 +++
> > 5 files changed, 210 insertions(+), 0 deletions(-)
> >
> > diff --git a/Documentation/devicetree/bindings/mfd/imx-syscon.txt b/Documentation/devicetree/bindings/mfd/imx-syscon.txt
> > new file mode 100644
> > index 0000000..c1a13b4
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/mfd/imx-syscon.txt
> > @@ -0,0 +1,11 @@
> > +* System Controller Registers R/W driver
> > +
> > +Required properties:
> > +- compatible: Should contain "syscon".
> > +- reg: the register range can be access from syscon
> > +
> > +Examples:
> > +gpr: iomuxc-gpr@020e0000 {
> > + compatible = "fsl,imx6q-iomuxc", "syscon";
> > + reg = <0x020e0000 0x38>;
> > +};
> > diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> > index b1a1462..4a6c48e 100644
> > --- a/drivers/mfd/Kconfig
> > +++ b/drivers/mfd/Kconfig
> > @@ -993,6 +993,13 @@ config MFD_ANATOP
> > MFD controller. This controller embeds regulator and
> > thermal devices for Freescale i.MX platforms.
> >
> > +config MFD_SYSCON
> > + bool "System Controller Register R/W Based on Regmap"
> > + select REGMAP_MMIO
> > + help
> > + Select this option to enable accessing system control registers
> > + via regmap.
> > +
> > config MFD_PALMAS
> > bool "Support for the TI Palmas series chips"
> > select MFD_CORE
> > diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
> > index 79dd22d..8384bc9 100644
> > --- a/drivers/mfd/Makefile
> > +++ b/drivers/mfd/Makefile
> > @@ -131,4 +131,5 @@ obj-$(CONFIG_MFD_PALMAS) += palmas.o
> > obj-$(CONFIG_MFD_RC5T583) += rc5t583.o rc5t583-irq.o
> > obj-$(CONFIG_MFD_SEC_CORE) += sec-core.o sec-irq.o
> > obj-$(CONFIG_MFD_ANATOP) += anatop-mfd.o
> > +obj-$(CONFIG_MFD_SYSCON) += syscon.o
> > obj-$(CONFIG_MFD_LM3533) += lm3533-core.o lm3533-ctrlbank.o
> > diff --git a/drivers/mfd/syscon.c b/drivers/mfd/syscon.c
> > new file mode 100644
> > index 0000000..da2464f
> > --- /dev/null
> > +++ b/drivers/mfd/syscon.c
> > @@ -0,0 +1,169 @@
> > +/*
> > + * System Control Driver
> > + *
> > + * Copyright (C) 2012 Freescale Semiconductor, Inc.
> > + * Copyright (C) 2012 Linaro Ltd.
> > + *
> > + * Author: Dong Aisheng <[email protected]>
> > + *
> > + * This program is free software; you can redistribute it and/or modify
> > + * it under the terms of the GNU General Public License as published by
> > + * the Free Software Foundation; either version 2 of the License, or
> > + * (at your option) any later version.
> > + */
> > +
> > +#include <linux/err.h>
> > +#include <linux/io.h>
> > +#include <linux/module.h>
> > +#include <linux/of.h>
> > +#include <linux/of_address.h>
> > +#include <linux/of_platform.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/regmap.h>
> > +
> > +static struct platform_driver syscon_driver;
> > +
> > +struct syscon {
> > + struct device *dev;
> > + void __iomem *base;
> > + struct regmap *regmap;
> > +};
> > +
> > +static int syscon_match(struct device *dev, void *data)
> > +{
> > + struct syscon *syscon = dev_get_drvdata(dev);
> > + struct device_node *dn = data;
> > +
> > + return (syscon->dev->of_node == dn) ? 1 : 0;
> > +}
> > +
> > +static struct regmap *syscon_node_to_regmap(struct device_node *np)
> > +{
> > + struct syscon *syscon;
> > + struct device *dev;
> > +
> > + dev = driver_find_device(&syscon_driver.driver, NULL, np,
> > + syscon_match);
> > + of_node_put(np);
> > +
> > + if (!dev)
> > + return ERR_PTR(-EPROBE_DEFER);
> > +
> > + syscon = dev_get_drvdata(dev);
> > +
> > + return syscon->regmap;
> > +}
> > +
> > +struct regmap *syscon_regmap_lookup_by_compatible(const char *s)
> > +{
> > + struct device_node *syscon_np;
> > +
> > + syscon_np = of_find_compatible_node(NULL, NULL, s);
> > + if (!syscon_np)
> > + return ERR_PTR(-ENODEV);
> > +
> > + return syscon_node_to_regmap(syscon_np);
> > +}
> > +
> > +struct regmap *syscon_regmap_lookup_by_phandle(struct device_node *np,
> > + const char *property)
> > +{
> > + struct device_node *syscon_np;
> > +
> > + syscon_np = of_parse_phandle(np, property, 0);
> > + if (!syscon_np)
> > + return ERR_PTR(-ENODEV);
> > +
> > + return syscon_node_to_regmap(syscon_np);
> > +}
>
> The above two APIs are all about finding the device_node for syscon,
> and can be done by clients in whatever way that is easy for them.
> Then we can save these APIs and export syscon_node_to_regmap directly.
>
Yes, we probably should also export syscon_node_to_regmap.
For other two, since they're common to be used, i prefer to keep them too
for user to choose to use, it saves client to write duplicate code.
> > +
> > +static const struct of_device_id of_syscon_match[] = {
> > + { .compatible = "syscon", },
> > + { },
> > +};
> > +
> > +static struct regmap_config syscon_regmap_config = {
> > + .reg_bits = 32,
> > + .val_bits = 32,
> > + .reg_stride = 4,
> > +};
> > +
> > +static int __devinit syscon_probe(struct platform_device *pdev)
> > +{
> > + struct device *dev = &pdev->dev;
> > + struct device_node *np = dev->of_node;
> > + struct syscon *syscon;
> > + struct resource res;
> > + int ret;
> > +
> > + if (!np)
> > + return -ENOENT;
> > +
> > + syscon = devm_kzalloc(&pdev->dev, sizeof(struct syscon),
> > + GFP_KERNEL);
> > + if (!syscon)
> > + return -ENOMEM;
> > +
> > + syscon->base = of_iomap(np, 0);
> > + if (!syscon->base)
> > + return -EADDRNOTAVAIL;
> > +
> > + ret = of_address_to_resource(np, 0, &res);
> > + if (ret)
> > + return ret;
> > +
> > + syscon_regmap_config.max_register = res.end - res.start - 3;
> > + syscon->regmap = devm_regmap_init_mmio(&pdev->dev, syscon->base,
> > + &syscon_regmap_config);
> > + if (IS_ERR(syscon->regmap)) {
> > + dev_err(&pdev->dev, "regmap init failed\n");
> > + return PTR_ERR(syscon->regmap);
> > + }
> > +
> > + regcache_cache_only(syscon->regmap, false);
> > +
> > + syscon->dev = &pdev->dev;
> > + platform_set_drvdata(pdev, syscon);
> > +
> > + dev_info(dev, "syscon regmap start 0x%x end 0x%x registered\n",
> > + res.start, res.end);
> > +
> > + return 0;
> > +}
> > +
> > +static int __devexit syscon_remove(struct platform_device *pdev)
> > +{
> > + struct syscon *syscon;
> > +
> > + syscon = platform_get_drvdata(pdev);
> > + iounmap(syscon->base);
> > + platform_set_drvdata(pdev, NULL);
> > +
> > + return 0;
> > +}
> > +
> > +static struct platform_driver syscon_driver = {
> > + .driver = {
> > + .name = "syscon",
> > + .owner = THIS_MODULE,
> > + .of_match_table = of_syscon_match,
> > + },
> > + .probe = syscon_probe,
> > + .remove = syscon_remove,
> > +};
> > +
> > +static int __init syscon_init(void)
> > +{
> > + return platform_driver_register(&syscon_driver);
> > +}
> > +postcore_initcall(syscon_init);
> > +
> > +static void __exit anatop_exit(void)
>
> s/anatop_exit/syscon_exit
>
> > +{
> > + platform_driver_unregister(&syscon_driver);
> > +}
> > +module_exit(anatop_exit);
>
> Ditto.
>
Correct, Thanks.
Will fix those typo in updated patches.
Regards
Dong Aisheng
> > +
> > +MODULE_AUTHOR("Dong Aisheng <[email protected]>");
> > +MODULE_DESCRIPTION("System Control driver");
> > +MODULE_LICENSE("GPL v2");
> > diff --git a/include/linux/mfd/syscon.h b/include/linux/mfd/syscon.h
> > new file mode 100644
> > index 0000000..990d7cf
> > --- /dev/null
> > +++ b/include/linux/mfd/syscon.h
> > @@ -0,0 +1,22 @@
> > +/*
> > + * System Control Driver
> > + *
> > + * Copyright (C) 2012 Freescale Semiconductor, Inc.
> > + * Copyright (C) 2012 Linaro Ltd.
> > + *
> > + * Author: Dong Aisheng <[email protected]>
> > + *
> > + * This program is free software; you can redistribute it and/or modify
> > + * it under the terms of the GNU General Public License as published by
> > + * the Free Software Foundation; either version 2 of the License, or
> > + * (at your option) any later version.
> > + */
> > +
> > +#ifndef __LINUX_MFD_SYSCON_H__
> > +#define __LINUX_MFD_SYSCON_H__
> > +
> > +extern struct regmap *syscon_regmap_lookup_by_compatible(const char *s);
> > +extern struct regmap *syscon_regmap_lookup_by_phandle(
> > + struct device_node *np,
> > + const char *property);
> > +#endif /* __LINUX_MFD_SYSCON_H__ */
> > --
> > 1.7.0.4
> >
> >
>
On Tue, Aug 28, 2012 at 06:15:35AM +0800, Shawn Guo wrote:
....
> > + sreg->anatop = syscon_regmap_lookup_by_phandle(np, "fsl,anatop");
> > + if (IS_ERR(sreg->anatop))
> > + return PTR_ERR(sreg->anatop);
> > +
>
> All the anatop regulators are child nodes of anatop. It looks a little
> odd to use phandle there. of_get_parent should just works.
>
Yes, this is a special case.
It's also ok for me to use of_get_parent if you want.
Will update it.
Regards
Dong Aisheng
On Mon, Aug 27, 2012 at 03:24:43PM +0800, Dong Aisheng wrote:
> From: Dong Aisheng <[email protected]>
>
> Using syscon to access anatop registers.
>
> Signed-off-by: Dong Aisheng <[email protected]>
> ---
> ChangeLog v1->v2:
> * update to use generic regmap api
> ---
> arch/arm/mach-imx/Kconfig | 2 +-
> arch/arm/mach-imx/mach-imx6q.c | 43 ++++++++++++++++-----------------------
> 2 files changed, 19 insertions(+), 26 deletions(-)
>
> diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
> index afd542a..7bba253 100644
> --- a/arch/arm/mach-imx/Kconfig
> +++ b/arch/arm/mach-imx/Kconfig
> @@ -839,7 +839,7 @@ config SOC_IMX6Q
> select HAVE_IMX_MMDC
> select HAVE_IMX_SRC
> select HAVE_SMP
> - select MFD_ANATOP
> + select MFD_SYSCON
> select PINCTRL
> select PINCTRL_IMX6Q
>
> diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c
> index 045b3f6..5de869a 100644
> --- a/arch/arm/mach-imx/mach-imx6q.c
> +++ b/arch/arm/mach-imx/mach-imx6q.c
> @@ -24,8 +24,9 @@
> #include <linux/of_platform.h>
> #include <linux/pinctrl/machine.h>
> #include <linux/phy.h>
> +#include <linux/regmap.h>
> #include <linux/micrel_phy.h>
> -#include <linux/mfd/anatop.h>
> +#include <linux/mfd/syscon.h>
> #include <asm/cpuidle.h>
> #include <asm/smp_twd.h>
> #include <asm/hardware/cache-l2x0.h>
> @@ -121,38 +122,30 @@ static void __init imx6q_sabrelite_init(void)
> static void __init imx6q_usb_init(void)
> {
> struct device_node *np;
> - struct platform_device *pdev = NULL;
> - struct anatop *adata = NULL;
> + struct regmap *anatop;
>
> np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-anatop");
np unused.
> - if (np)
> - pdev = of_find_device_by_node(np);
> - if (pdev)
> - adata = platform_get_drvdata(pdev);
> - if (!adata) {
> - if (np)
> - of_node_put(np);
> - return;
> - }
> -
> #define HW_ANADIG_USB1_CHRG_DETECT 0x000001b0
> #define HW_ANADIG_USB2_CHRG_DETECT 0x00000210
>
> #define BM_ANADIG_USB_CHRG_DETECT_EN_B 0x00100000
> #define BM_ANADIG_USB_CHRG_DETECT_CHK_CHRG_B 0x00080000
>
> - /*
> - * The external charger detector needs to be disabled,
> - * or the signal at DP will be poor
> - */
> - anatop_write_reg(adata, HW_ANADIG_USB1_CHRG_DETECT,
> - BM_ANADIG_USB_CHRG_DETECT_EN_B
> - | BM_ANADIG_USB_CHRG_DETECT_CHK_CHRG_B,
> - ~0);
> - anatop_write_reg(adata, HW_ANADIG_USB2_CHRG_DETECT,
> - BM_ANADIG_USB_CHRG_DETECT_EN_B |
> - BM_ANADIG_USB_CHRG_DETECT_CHK_CHRG_B,
> - ~0);
> + anatop = syscon_regmap_lookup_by_compatible("fsl,imx6q-anatop");
> + if (!IS_ERR(anatop)) {
> + /*
> + * The external charger detector needs to be disabled,
> + * or the signal at DP will be poor
> + */
> + regmap_write(anatop, HW_ANADIG_USB1_CHRG_DETECT,
> + BM_ANADIG_USB_CHRG_DETECT_EN_B
> + | BM_ANADIG_USB_CHRG_DETECT_CHK_CHRG_B);
> + regmap_write(anatop, HW_ANADIG_USB2_CHRG_DETECT,
> + BM_ANADIG_USB_CHRG_DETECT_EN_B |
> + BM_ANADIG_USB_CHRG_DETECT_CHK_CHRG_B);
> + } else {
> + pr_warn("failed to find fsl,imx6q-anatop regmap\n");
> + }
>
> of_node_put(np);
unneeded.
Thanks
Richard
> }
> --
> 1.7.0.4
>
On Tue, Aug 28, 2012 at 11:23:10AM +0800, Zhao Richard-B20223 wrote:
...
> > np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-anatop");
> np unused.
Correct.
Will drop it.
Regards
Dong Aisheng