diff options
author | Shawn Guo <shawn.guo@linaro.org> | 2012-07-13 14:15:34 +0800 |
---|---|---|
committer | Shawn Guo <shawn.guo@linaro.org> | 2012-08-17 12:35:09 +0800 |
commit | 2c7c2c1d01a2559d452c0f0aa5e6f6ca2643e6b1 (patch) | |
tree | f2ec81a772baaa2e65986864c30a9bf503fd9e04 /arch/arm/mach-mxs | |
parent | aef35104a9e5b8555cdaeebd4563df9921f6d605 (diff) |
ARM: mxs: tx28: reset fec phy for device tree boot
For non-DT boot, function tx28_add_fec0 configures all ENET0 pins
into gpio mode for resetting fec phy, and then reconfigures those pins
into ENET function after that.
For DT boot, all the pin configuration is done by pinctrl subsystem.
Ideally, when gpio_request gets called, GPIO subsystem should call
pinctrl to configure pins into gpio mode automatically, and have pins
freed up from pinctrl subsystem when gpio_free is called. But right
now, this cooperation between gpio and pinctrl hasn't been available.
As the result, we have to explicitly call pinctrl_get_select and
pinctrl_put for device tree boot.
Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
Acked-by: Lothar Waßmann <LW@KARO-electronics.de>
Diffstat (limited to 'arch/arm/mach-mxs')
-rw-r--r-- | arch/arm/mach-mxs/mach-mxs.c | 82 |
1 files changed, 81 insertions, 1 deletions
diff --git a/arch/arm/mach-mxs/mach-mxs.c b/arch/arm/mach-mxs/mach-mxs.c index ceb73984478..8378fe5cfaf 100644 --- a/arch/arm/mach-mxs/mach-mxs.c +++ b/arch/arm/mach-mxs/mach-mxs.c @@ -12,8 +12,9 @@ #include <linux/clk.h> #include <linux/clkdev.h> +#include <linux/delay.h> #include <linux/err.h> -#include <linux/init.h> +#include <linux/gpio.h> #include <linux/init.h> #include <linux/irqdomain.h> #include <linux/micrel_phy.h> @@ -21,10 +22,12 @@ #include <linux/of_irq.h> #include <linux/of_platform.h> #include <linux/phy.h> +#include <linux/pinctrl/consumer.h> #include <asm/mach/arch.h> #include <asm/mach/time.h> #include <mach/common.h> #include <mach/digctl.h> +#include <mach/mxs.h> static struct fb_videomode mx23evk_video_modes[] = { { @@ -273,6 +276,80 @@ static void __init apx4devkit_init(void) mxsfb_pdata.ld_intf_width = STMLCDIF_24BIT; } +#define ENET0_MDC__GPIO_4_0 MXS_GPIO_NR(4, 0) +#define ENET0_MDIO__GPIO_4_1 MXS_GPIO_NR(4, 1) +#define ENET0_RX_EN__GPIO_4_2 MXS_GPIO_NR(4, 2) +#define ENET0_RXD0__GPIO_4_3 MXS_GPIO_NR(4, 3) +#define ENET0_RXD1__GPIO_4_4 MXS_GPIO_NR(4, 4) +#define ENET0_TX_EN__GPIO_4_6 MXS_GPIO_NR(4, 6) +#define ENET0_TXD0__GPIO_4_7 MXS_GPIO_NR(4, 7) +#define ENET0_TXD1__GPIO_4_8 MXS_GPIO_NR(4, 8) +#define ENET_CLK__GPIO_4_16 MXS_GPIO_NR(4, 16) + +#define TX28_FEC_PHY_POWER MXS_GPIO_NR(3, 29) +#define TX28_FEC_PHY_RESET MXS_GPIO_NR(4, 13) +#define TX28_FEC_nINT MXS_GPIO_NR(4, 5) + +static const struct gpio tx28_gpios[] __initconst = { + { ENET0_MDC__GPIO_4_0, GPIOF_OUT_INIT_LOW, "GPIO_4_0" }, + { ENET0_MDIO__GPIO_4_1, GPIOF_OUT_INIT_LOW, "GPIO_4_1" }, + { ENET0_RX_EN__GPIO_4_2, GPIOF_OUT_INIT_LOW, "GPIO_4_2" }, + { ENET0_RXD0__GPIO_4_3, GPIOF_OUT_INIT_LOW, "GPIO_4_3" }, + { ENET0_RXD1__GPIO_4_4, GPIOF_OUT_INIT_LOW, "GPIO_4_4" }, + { ENET0_TX_EN__GPIO_4_6, GPIOF_OUT_INIT_LOW, "GPIO_4_6" }, + { ENET0_TXD0__GPIO_4_7, GPIOF_OUT_INIT_LOW, "GPIO_4_7" }, + { ENET0_TXD1__GPIO_4_8, GPIOF_OUT_INIT_LOW, "GPIO_4_8" }, + { ENET_CLK__GPIO_4_16, GPIOF_OUT_INIT_LOW, "GPIO_4_16" }, + { TX28_FEC_PHY_POWER, GPIOF_OUT_INIT_LOW, "fec-phy-power" }, + { TX28_FEC_PHY_RESET, GPIOF_OUT_INIT_LOW, "fec-phy-reset" }, + { TX28_FEC_nINT, GPIOF_DIR_IN, "fec-int" }, +}; + +static void __init tx28_post_init(void) +{ + struct device_node *np; + struct platform_device *pdev; + struct pinctrl *pctl; + int ret; + + enable_clk_enet_out(); + + np = of_find_compatible_node(NULL, NULL, "fsl,imx28-fec"); + pdev = of_find_device_by_node(np); + if (!pdev) { + pr_err("%s: failed to find fec device\n", __func__); + return; + } + + pctl = pinctrl_get_select(&pdev->dev, "gpio_mode"); + if (IS_ERR(pctl)) { + pr_err("%s: failed to get pinctrl state\n", __func__); + return; + } + + ret = gpio_request_array(tx28_gpios, ARRAY_SIZE(tx28_gpios)); + if (ret) { + pr_err("%s: failed to request gpios: %d\n", __func__, ret); + return; + } + + /* Power up fec phy */ + gpio_set_value(TX28_FEC_PHY_POWER, 1); + msleep(26); /* 25ms according to data sheet */ + + /* Mode strap pins */ + gpio_set_value(ENET0_RX_EN__GPIO_4_2, 1); + gpio_set_value(ENET0_RXD0__GPIO_4_3, 1); + gpio_set_value(ENET0_RXD1__GPIO_4_4, 1); + + udelay(100); /* minimum assertion time for nRST */ + + /* Deasserting FEC PHY RESET */ + gpio_set_value(TX28_FEC_PHY_RESET, 1); + + pinctrl_put(pctl); +} + static void __init mxs_machine_init(void) { if (of_machine_is_compatible("fsl,imx28-evk")) @@ -286,6 +363,9 @@ static void __init mxs_machine_init(void) of_platform_populate(NULL, of_default_bus_match_table, mxs_auxdata_lookup, NULL); + + if (of_machine_is_compatible("karo,tx28")) + tx28_post_init(); } static const char *imx23_dt_compat[] __initdata = { |