add support for configuring the pinmux on davinci SoC through OF. Signed-off-by: Heiko Schocher <h...@denx.de> Cc: davinci-linux-open-source@linux.davincidsp.com Cc: linux-arm-ker...@lists.infradead.org Cc: devicetree-disc...@lists.ozlabs.org Cc: Grant Likely <grant.lik...@secretlab.ca> Cc: Sekhar Nori <nsek...@ti.com> Cc: Wolfgang Denk <w...@denx.de>
--- This patch is just a RFC, as I want to get rid of the pin setup code in board code ... This patch introduces a davinci_cfg_reg_of() function, which davinci drivers can call, if they found a pinmux-handle, so used in the following drivers in this patchserie: drivers/net/ethernet/ti/davinci_emac drivers/i2c/busses/i2c-davinci.c drivers/mtd/nand/davinci_nand.c Comments are welcome. - no changes for v2 - no changes for v3 .../devicetree/bindings/arm/davinci/mux.txt | 40 +++++++++++ arch/arm/mach-davinci/include/mach/mux.h | 2 + arch/arm/mach-davinci/mux.c | 73 +++++++++++++++++++- 3 files changed, 114 insertions(+), 1 deletions(-) create mode 100644 Documentation/devicetree/bindings/arm/davinci/mux.txt diff --git a/Documentation/devicetree/bindings/arm/davinci/mux.txt b/Documentation/devicetree/bindings/arm/davinci/mux.txt new file mode 100644 index 0000000..ecb026a --- /dev/null +++ b/Documentation/devicetree/bindings/arm/davinci/mux.txt @@ -0,0 +1,40 @@ +* Texas Instruments Davinci pinmux + +This file provides information, what the device node for the +davinci pinmux interface contain. + +Required properties: +- compatible: "ti,davinci-pinmux"; +- pins : contains a table with the following colums: + mux register: pinmux register + register offset: offset in register, which to change + mode mask: mode mask + mode value: mode value + +Optional properties: +- none + +Example (enbw_cmc board): + emac_pins: pinmux@1c14120 { + compatible = "ti,davinci-pinmux"; + reg = <0x14120 0x1000>; + pins = < /* muxreg maskoff modemsk muxmode */ + 2 4 15 8 /* MII TXEN */ + 2 8 15 8 /* MII TXCLK */ + 2 12 15 8 /* MII COL */ + 2 16 15 8 /* MII TXD_3 */ + 2 20 15 8 /* MII TXD_2 */ + 2 24 15 8 /* MII TXD_1 */ + 2 28 15 8 /* MII TXD_0 */ + 3 8 15 8 /* MII RXER */ + 3 12 15 8 /* MII CRS */ + 3 0 15 8 /* MII RXCLK */ + 3 4 15 8 /* MII RXDV */ + 3 16 15 8 /* MII RXD_3 */ + 3 20 15 8 /* MII RXD_2 */ + 3 24 15 8 /* MII RXD_1 */ + 3 28 15 8 /* MII RXD_0 */ + 4 0 15 8 /* MDIO CLK */ + 4 4 15 8 /* MDIO D */ + >; + }; diff --git a/arch/arm/mach-davinci/include/mach/mux.h b/arch/arm/mach-davinci/include/mach/mux.h index a7e92fc..3a62857 100644 --- a/arch/arm/mach-davinci/include/mach/mux.h +++ b/arch/arm/mach-davinci/include/mach/mux.h @@ -1205,6 +1205,7 @@ enum davinci_tnetv107x_index { /* setup pin muxing */ extern int davinci_cfg_reg(unsigned long reg_cfg); extern int davinci_cfg_reg_list(const short pins[]); +extern int davinci_cfg_reg_of(struct device_node *); #else /* boot loader does it all (no warnings from CONFIG_DAVINCI_MUX_WARNINGS) */ static inline int davinci_cfg_reg(unsigned long reg_cfg) { return 0; } @@ -1212,6 +1213,7 @@ static inline int davinci_cfg_reg_list(const short pins[]) { return 0; } +static int davinci_cfg_reg_of(struct device_node *) { return 0; }; #endif #endif /* __INC_MACH_MUX_H */ diff --git a/arch/arm/mach-davinci/mux.c b/arch/arm/mach-davinci/mux.c index f34a8dc..6b38072 100644 --- a/arch/arm/mach-davinci/mux.c +++ b/arch/arm/mach-davinci/mux.c @@ -18,18 +18,21 @@ #include <linux/io.h> #include <linux/module.h> #include <linux/spinlock.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/slab.h> #include <mach/mux.h> #include <mach/common.h> static void __iomem *pinmux_base; +static DEFINE_SPINLOCK(mux_spin_lock); /* * Sets the DAVINCI MUX register based on the table */ int __init_or_module davinci_cfg_reg(const unsigned long index) { - static DEFINE_SPINLOCK(mux_spin_lock); struct davinci_soc_info *soc_info = &davinci_soc_info; unsigned long flags; const struct mux_config *cfg; @@ -98,6 +101,74 @@ int __init_or_module davinci_cfg_reg(const unsigned long index) } EXPORT_SYMBOL(davinci_cfg_reg); +#ifdef CONFIG_OF +int davinci_cfg_reg_of(struct device_node *np) +{ + unsigned long flags; + int pinmux_map_len; + const unsigned int *pinmux_map; + u32 muxreg, maskoff, modemsk, muxmode; + unsigned int reg_orig = 0, reg = 0; + unsigned int mask, warn = 0; + + pinmux_map = of_get_property(np, "pins", &pinmux_map_len); + if (pinmux_map == NULL) { + printk(KERN_ERR "pins is not set!\n"); + return -EINVAL; + } + + pinmux_map_len /= sizeof(unsigned int); + if ((pinmux_map_len % 4) != 0) { + printk(KERN_ERR "pins format wrong!\n"); + return -EINVAL; + } + + if (!pinmux_base) { + pinmux_base = of_iomap(np, 0); + if (WARN_ON(!pinmux_base)) + return -ENOMEM; + } + + while (pinmux_map_len > 0) { + muxreg = be32_to_cpu(pinmux_map[0]); + maskoff = be32_to_cpu(pinmux_map[1]); + modemsk = be32_to_cpu(pinmux_map[2]); + muxmode = be32_to_cpu(pinmux_map[3]); + + /* Update the mux register in question */ + if (modemsk) { + unsigned tmp1, tmp2; + + spin_lock_irqsave(&mux_spin_lock, flags); + reg_orig = __raw_readl(pinmux_base + muxreg); + + mask = (modemsk << maskoff); + tmp1 = reg_orig & mask; + reg = reg_orig & ~mask; + + tmp2 = (muxmode << maskoff); + reg |= tmp2; + + if (tmp1 != tmp2) + warn = 1; + + __raw_writel(reg, pinmux_base + muxreg); + spin_unlock_irqrestore(&mux_spin_lock, flags); + } + pinmux_map += 4; + pinmux_map_len -= 4; + } + + return 0; +} +#else +int davinci_cfg_reg_of(struct device_node *np) +{ + return 0; +} +#endif +EXPORT_SYMBOL(davinci_cfg_reg_of); + int __init_or_module davinci_cfg_reg_list(const short pins[]) { int i, error = -EINVAL; -- 1.7.7.6 _______________________________________________ Davinci-linux-open-source mailing list Davinci-linux-open-source@linux.davincidsp.com http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source