summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFabio Estevam <fabio.estevam@freescale.com>2013-06-10 23:12:57 -0300
committerMarc Kleine-Budde <mkl@pengutronix.de>2013-06-27 15:15:25 +0200
commitb7c4114b07bbacfe0aee1d04ad1ade9e42309620 (patch)
treec21e4f17d4149674db3761dd782c3f8056662f81
parent30caa4b763bf5973800633de55bae586ab443f78 (diff)
downloadlinux-stable-b7c4114b07bbacfe0aee1d04ad1ade9e42309620.tar.gz
linux-stable-b7c4114b07bbacfe0aee1d04ad1ade9e42309620.tar.bz2
linux-stable-b7c4114b07bbacfe0aee1d04ad1ade9e42309620.zip
can: flexcan: Use a regulator to control the CAN transceiver
Instead of using a GPIO to turn on/off the CAN transceiver, it is better to use a regulator as some systems may use a PMIC to power the CAN transceiver. Acked-by: Shawn Guo <shawn.guo@linaro.org> Signed-off-by: Fabio Estevam <fabio.estevam@freescale.com> Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
-rw-r--r--Documentation/devicetree/bindings/net/can/fsl-flexcan.txt2
-rw-r--r--arch/arm/boot/dts/imx28-evk.dts12
-rw-r--r--arch/arm/mach-mxs/mach-mxs.c50
-rw-r--r--drivers/net/can/flexcan.c25
4 files changed, 28 insertions, 61 deletions
diff --git a/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt b/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt
index 8ff324eaa889..56d6cc336e1c 100644
--- a/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt
+++ b/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt
@@ -16,6 +16,8 @@ Optional properties:
- clock-frequency : The oscillator frequency driving the flexcan device
+- xceiver-supply: Regulator that powers the CAN transceiver
+
Example:
can@1c000 {
diff --git a/arch/arm/boot/dts/imx28-evk.dts b/arch/arm/boot/dts/imx28-evk.dts
index 3637bf3b1d59..1f0d38d7b16f 100644
--- a/arch/arm/boot/dts/imx28-evk.dts
+++ b/arch/arm/boot/dts/imx28-evk.dts
@@ -155,12 +155,14 @@
can0: can@80032000 {
pinctrl-names = "default";
pinctrl-0 = <&can0_pins_a>;
+ xceiver-supply = <&reg_can_3v3>;
status = "okay";
};
can1: can@80034000 {
pinctrl-names = "default";
pinctrl-0 = <&can1_pins_a>;
+ xceiver-supply = <&reg_can_3v3>;
status = "okay";
};
};
@@ -319,6 +321,16 @@
gpio = <&gpio3 30 0>;
enable-active-high;
};
+
+ reg_can_3v3: can-3v3 {
+ compatible = "regulator-fixed";
+ regulator-name = "can-3v3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ gpio = <&gpio2 13 0>;
+ enable-active-high;
+ };
+
};
sound {
diff --git a/arch/arm/mach-mxs/mach-mxs.c b/arch/arm/mach-mxs/mach-mxs.c
index 5b62b6489d4b..97b8a44101cd 100644
--- a/arch/arm/mach-mxs/mach-mxs.c
+++ b/arch/arm/mach-mxs/mach-mxs.c
@@ -14,7 +14,6 @@
#include <linux/clk/mxs.h>
#include <linux/clkdev.h>
#include <linux/clocksource.h>
-#include <linux/can/platform/flexcan.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/gpio.h>
@@ -60,41 +59,6 @@ static inline void __mxs_togl(u32 mask, void __iomem *reg)
__raw_writel(mask, reg + MXS_TOG_ADDR);
}
-/*
- * MX28EVK_FLEXCAN_SWITCH is shared between both flexcan controllers
- */
-#define MX28EVK_FLEXCAN_SWITCH MXS_GPIO_NR(2, 13)
-
-static int flexcan0_en, flexcan1_en;
-
-static void mx28evk_flexcan_switch(void)
-{
- if (flexcan0_en || flexcan1_en)
- gpio_set_value(MX28EVK_FLEXCAN_SWITCH, 1);
- else
- gpio_set_value(MX28EVK_FLEXCAN_SWITCH, 0);
-}
-
-static void mx28evk_flexcan0_switch(int enable)
-{
- flexcan0_en = enable;
- mx28evk_flexcan_switch();
-}
-
-static void mx28evk_flexcan1_switch(int enable)
-{
- flexcan1_en = enable;
- mx28evk_flexcan_switch();
-}
-
-static struct flexcan_platform_data flexcan_pdata[2];
-
-static struct of_dev_auxdata mxs_auxdata_lookup[] __initdata = {
- OF_DEV_AUXDATA("fsl,imx28-flexcan", 0x80032000, NULL, &flexcan_pdata[0]),
- OF_DEV_AUXDATA("fsl,imx28-flexcan", 0x80034000, NULL, &flexcan_pdata[1]),
- { /* sentinel */ }
-};
-
#define OCOTP_WORD_OFFSET 0x20
#define OCOTP_WORD_COUNT 0x20
@@ -254,15 +218,6 @@ static void __init imx28_evk_init(void)
mxs_saif_clkmux_select(MXS_DIGCTL_SAIF_CLKMUX_EXTMSTR0);
}
-static void __init imx28_evk_post_init(void)
-{
- if (!gpio_request_one(MX28EVK_FLEXCAN_SWITCH, GPIOF_DIR_OUT,
- "flexcan-switch")) {
- flexcan_pdata[0].transceiver_switch = mx28evk_flexcan0_switch;
- flexcan_pdata[1].transceiver_switch = mx28evk_flexcan1_switch;
- }
-}
-
static int apx4devkit_phy_fixup(struct phy_device *phy)
{
phy->dev_flags |= MICREL_PHY_50MHZ_CLK;
@@ -374,13 +329,10 @@ static void __init mxs_machine_init(void)
cfa10049_init();
of_platform_populate(NULL, of_default_bus_match_table,
- mxs_auxdata_lookup, NULL);
+ NULL, NULL);
if (of_machine_is_compatible("karo,tx28"))
tx28_post_init();
-
- if (of_machine_is_compatible("fsl,imx28-evk"))
- imx28_evk_post_init();
}
#define MX23_CLKCTRL_RESET_OFFSET 0x120
diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c
index f873b9f8d4d4..7b0be0910f4b 100644
--- a/drivers/net/can/flexcan.c
+++ b/drivers/net/can/flexcan.c
@@ -24,7 +24,6 @@
#include <linux/can/dev.h>
#include <linux/can/error.h>
#include <linux/can/led.h>
-#include <linux/can/platform/flexcan.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/if_arp.h>
@@ -37,6 +36,7 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
#define DRV_NAME "flexcan"
@@ -211,6 +211,7 @@ struct flexcan_priv {
struct clk *clk_per;
struct flexcan_platform_data *pdata;
const struct flexcan_devtype_data *devtype_data;
+ struct regulator *reg_xceiver;
};
static struct flexcan_devtype_data fsl_p1010_devtype_data = {
@@ -258,15 +259,6 @@ static inline void flexcan_write(u32 val, void __iomem *addr)
}
#endif
-/*
- * Swtich transceiver on or off
- */
-static void flexcan_transceiver_switch(const struct flexcan_priv *priv, int on)
-{
- if (priv->pdata && priv->pdata->transceiver_switch)
- priv->pdata->transceiver_switch(on);
-}
-
static inline int flexcan_has_and_handle_berr(const struct flexcan_priv *priv,
u32 reg_esr)
{
@@ -799,7 +791,11 @@ static int flexcan_chip_start(struct net_device *dev)
if (priv->devtype_data->features & FLEXCAN_HAS_V10_FEATURES)
flexcan_write(0x0, &regs->rxfgmask);
- flexcan_transceiver_switch(priv, 1);
+ if (priv->reg_xceiver) {
+ err = regulator_enable(priv->reg_xceiver);
+ if (err)
+ goto out;
+ }
/* synchronize with the can bus */
reg_mcr = flexcan_read(&regs->mcr);
@@ -842,7 +838,8 @@ static void flexcan_chip_stop(struct net_device *dev)
reg |= FLEXCAN_MCR_MDIS | FLEXCAN_MCR_HALT;
flexcan_write(reg, &regs->mcr);
- flexcan_transceiver_switch(priv, 0);
+ if (priv->reg_xceiver)
+ regulator_disable(priv->reg_xceiver);
priv->can.state = CAN_STATE_STOPPED;
return;
@@ -1084,6 +1081,10 @@ static int flexcan_probe(struct platform_device *pdev)
priv->pdata = pdev->dev.platform_data;
priv->devtype_data = devtype_data;
+ priv->reg_xceiver = devm_regulator_get(&pdev->dev, "xceiver");
+ if (IS_ERR(priv->reg_xceiver))
+ priv->reg_xceiver = NULL;
+
netif_napi_add(dev, &priv->napi, flexcan_poll, FLEXCAN_NAPI_WEIGHT);
dev_set_drvdata(&pdev->dev, dev);