mirror of
https://github.com/genesi/linux-legacy.git
synced 2026-09-24 15:44:22 +00:00
632 lines
15 KiB
C
632 lines
15 KiB
C
/*
|
|
* Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved.
|
|
*/
|
|
|
|
/*
|
|
* The code contained herein is licensed under the GNU General Public
|
|
* License. You may obtain a copy of the GNU General Public License
|
|
* Version 2 or later at the following locations:
|
|
*
|
|
* http://www.opensource.org/licenses/gpl-license.html
|
|
* http://www.gnu.org/copyleft/gpl.html
|
|
*/
|
|
|
|
/*!
|
|
* @file drv.c
|
|
*
|
|
* @brief Driver for Freescale CAN Controller FlexCAN.
|
|
*
|
|
* @ingroup can
|
|
*/
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/init.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/netdevice.h>
|
|
#include <linux/if_arp.h>
|
|
#include <linux/if_ether.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/regulator/consumer.h>
|
|
#include <linux/clk.h>
|
|
#ifdef CONFIG_ARCH_MXS
|
|
#include <mach/device.h>
|
|
#endif
|
|
|
|
#include <asm/io.h>
|
|
#include <asm/irq.h>
|
|
#include <mach/hardware.h>
|
|
#include "flexcan.h"
|
|
|
|
static void flexcan_hw_start(struct flexcan_device *flexcan)
|
|
{
|
|
unsigned int reg;
|
|
if ((flexcan->maxmb + 1) > 32) {
|
|
__raw_writel(0xFFFFFFFF, flexcan->io_base + CAN_HW_REG_IMASK1);
|
|
reg = (1 << (flexcan->maxmb - 31)) - 1;
|
|
__raw_writel(reg, flexcan->io_base + CAN_HW_REG_IMASK2);
|
|
} else {
|
|
reg = (1 << (flexcan->maxmb + 1)) - 1;
|
|
__raw_writel(reg, flexcan->io_base + CAN_HW_REG_IMASK1);
|
|
__raw_writel(0, flexcan->io_base + CAN_HW_REG_IMASK2);
|
|
}
|
|
|
|
reg = __raw_readl(flexcan->io_base + CAN_HW_REG_MCR) & (~__MCR_HALT);
|
|
__raw_writel(reg, flexcan->io_base + CAN_HW_REG_MCR);
|
|
}
|
|
|
|
static void flexcan_hw_stop(struct flexcan_device *flexcan)
|
|
{
|
|
unsigned int reg;
|
|
reg = __raw_readl(flexcan->io_base + CAN_HW_REG_MCR);
|
|
__raw_writel(reg | __MCR_HALT, flexcan->io_base + CAN_HW_REG_MCR);
|
|
}
|
|
|
|
static int flexcan_hw_reset(struct flexcan_device *flexcan)
|
|
{
|
|
unsigned int reg;
|
|
int timeout = 100000;
|
|
|
|
reg = __raw_readl(flexcan->io_base + CAN_HW_REG_MCR);
|
|
__raw_writel(reg | __MCR_MDIS, flexcan->io_base + CAN_HW_REG_MCR);
|
|
|
|
reg = __raw_readl(flexcan->io_base + CAN_HW_REG_CTRL);
|
|
if (flexcan->br_clksrc)
|
|
reg |= __CTRL_CLK_SRC;
|
|
else
|
|
reg &= ~__CTRL_CLK_SRC;
|
|
__raw_writel(reg, flexcan->io_base + CAN_HW_REG_CTRL);
|
|
|
|
reg = __raw_readl(flexcan->io_base + CAN_HW_REG_MCR) & (~__MCR_MDIS);
|
|
__raw_writel(reg, flexcan->io_base + CAN_HW_REG_MCR);
|
|
reg |= __MCR_SOFT_RST;
|
|
__raw_writel(reg, flexcan->io_base + CAN_HW_REG_MCR);
|
|
|
|
reg = __raw_readl(flexcan->io_base + CAN_HW_REG_MCR);
|
|
while (reg & __MCR_SOFT_RST) {
|
|
if (--timeout <= 0) {
|
|
printk(KERN_ERR "Flexcan software Reset Timeouted\n");
|
|
return -1;
|
|
}
|
|
udelay(10);
|
|
reg = __raw_readl(flexcan->io_base + CAN_HW_REG_MCR);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static inline void flexcan_mcr_setup(struct flexcan_device *flexcan)
|
|
{
|
|
unsigned int reg;
|
|
|
|
reg = __raw_readl(flexcan->io_base + CAN_HW_REG_MCR);
|
|
reg &= ~(__MCR_MAX_MB_MASK | __MCR_WAK_MSK | __MCR_MAX_IDAM_MASK);
|
|
|
|
if (flexcan->fifo)
|
|
reg |= __MCR_FEN;
|
|
else
|
|
reg &= ~__MCR_FEN;
|
|
|
|
if (flexcan->wakeup)
|
|
reg |= __MCR_SLF_WAK | __MCR_WAK_MSK;
|
|
else
|
|
reg &= ~(__MCR_SLF_WAK | __MCR_WAK_MSK);
|
|
|
|
if (flexcan->wak_src)
|
|
reg |= __MCR_WAK_SRC;
|
|
else
|
|
reg &= ~__MCR_WAK_SRC;
|
|
|
|
if (flexcan->srx_dis)
|
|
reg |= __MCR_SRX_DIS;
|
|
else
|
|
reg &= ~__MCR_SRX_DIS;
|
|
|
|
if (flexcan->bcc)
|
|
reg |= __MCR_BCC;
|
|
else
|
|
reg &= ~__MCR_BCC;
|
|
|
|
if (flexcan->lprio)
|
|
reg |= __MCR_LPRIO_EN;
|
|
else
|
|
reg &= ~__MCR_LPRIO_EN;
|
|
|
|
if (flexcan->abort)
|
|
reg |= __MCR_AEN;
|
|
else
|
|
reg &= ~__MCR_AEN;
|
|
|
|
reg |= (flexcan->maxmb << __MCR_MAX_MB_OFFSET);
|
|
reg |= __MCR_DOZE | __MCR_MAX_IDAM_C;
|
|
__raw_writel(reg, flexcan->io_base + CAN_HW_REG_MCR);
|
|
}
|
|
|
|
static inline void flexcan_ctrl_setup(struct flexcan_device *flexcan)
|
|
{
|
|
unsigned int reg;
|
|
|
|
reg = __raw_readl(flexcan->io_base + CAN_HW_REG_CTRL);
|
|
reg &= ~(__CTRL_PRESDIV_MASK | __CTRL_RJW_MASK | __CTRL_PSEG1_MASK |
|
|
__CTRL_PSEG2_MASK | __CTRL_PROPSEG_MASK);
|
|
|
|
if (flexcan->loopback)
|
|
reg |= __CTRL_LPB;
|
|
else
|
|
reg &= ~__CTRL_LPB;
|
|
|
|
if (flexcan->smp)
|
|
reg |= __CTRL_SMP;
|
|
else
|
|
reg &= ~__CTRL_SMP;
|
|
|
|
if (flexcan->boff_rec)
|
|
reg |= __CTRL_BOFF_REC;
|
|
else
|
|
reg &= ~__CTRL_BOFF_REC;
|
|
|
|
if (flexcan->tsyn)
|
|
reg |= __CTRL_TSYN;
|
|
else
|
|
reg &= ~__CTRL_TSYN;
|
|
|
|
if (flexcan->listen)
|
|
reg |= __CTRL_LOM;
|
|
else
|
|
reg &= ~__CTRL_LOM;
|
|
|
|
reg |= (flexcan->br_presdiv << __CTRL_PRESDIV_OFFSET) |
|
|
(flexcan->br_rjw << __CTRL_RJW_OFFSET) |
|
|
(flexcan->br_pseg1 << __CTRL_PSEG1_OFFSET) |
|
|
(flexcan->br_pseg2 << __CTRL_PSEG2_OFFSET) |
|
|
(flexcan->br_propseg << __CTRL_PROPSEG_OFFSET);
|
|
|
|
reg &= ~__CTRL_LBUF;
|
|
|
|
reg |= __CTRL_TWRN_MSK | __CTRL_RWRN_MSK | __CTRL_BOFF_MSK |
|
|
__CTRL_ERR_MSK;
|
|
|
|
__raw_writel(reg, flexcan->io_base + CAN_HW_REG_CTRL);
|
|
}
|
|
|
|
static int flexcan_hw_restart(struct net_device *dev)
|
|
{
|
|
unsigned int reg;
|
|
struct flexcan_device *flexcan = netdev_priv(dev);
|
|
|
|
reg = __raw_readl(flexcan->io_base + CAN_HW_REG_MCR);
|
|
if (reg & __MCR_SOFT_RST)
|
|
return 1;
|
|
|
|
flexcan_mcr_setup(flexcan);
|
|
|
|
__raw_writel(0, flexcan->io_base + CAN_HW_REG_IMASK2);
|
|
__raw_writel(0, flexcan->io_base + CAN_HW_REG_IMASK1);
|
|
|
|
__raw_writel(0xFFFFFFFF, flexcan->io_base + CAN_HW_REG_IFLAG2);
|
|
__raw_writel(0xFFFFFFFF, flexcan->io_base + CAN_HW_REG_IFLAG1);
|
|
|
|
__raw_writel(0, flexcan->io_base + CAN_HW_REG_ECR);
|
|
|
|
flexcan_mbm_init(flexcan);
|
|
netif_carrier_on(dev);
|
|
flexcan_hw_start(flexcan);
|
|
|
|
if (netif_queue_stopped(dev))
|
|
netif_start_queue(dev);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void flexcan_hw_watch(unsigned long data)
|
|
{
|
|
unsigned int reg, ecr;
|
|
struct net_device *dev = (struct net_device *)data;
|
|
struct flexcan_device *flexcan = dev ? netdev_priv(dev) : NULL;
|
|
|
|
BUG_ON(!flexcan);
|
|
|
|
reg = __raw_readl(flexcan->io_base + CAN_HW_REG_MCR);
|
|
if (reg & __MCR_MDIS) {
|
|
if (flexcan_hw_restart(dev))
|
|
mod_timer(&flexcan->timer, HZ / 20);
|
|
return;
|
|
}
|
|
ecr = __raw_readl(flexcan->io_base + CAN_HW_REG_ECR);
|
|
if (flexcan->boff_rec) {
|
|
if (((reg & __ESR_FLT_CONF_MASK) >> __ESR_FLT_CONF_OFF) > 1) {
|
|
reg |= __MCR_SOFT_RST;
|
|
__raw_writel(reg, flexcan->io_base + CAN_HW_REG_MCR);
|
|
mod_timer(&flexcan->timer, HZ / 20);
|
|
return;
|
|
}
|
|
netif_carrier_on(dev);
|
|
}
|
|
}
|
|
|
|
static void flexcan_hw_busoff(struct net_device *dev)
|
|
{
|
|
struct flexcan_device *flexcan = netdev_priv(dev);
|
|
unsigned int reg;
|
|
|
|
netif_carrier_off(dev);
|
|
|
|
flexcan->timer.function = flexcan_hw_watch;
|
|
flexcan->timer.data = (unsigned long)dev;
|
|
|
|
if (flexcan->boff_rec) {
|
|
mod_timer(&flexcan->timer, HZ / 10);
|
|
return;
|
|
}
|
|
reg = __raw_readl(flexcan->io_base + CAN_HW_REG_MCR);
|
|
__raw_writel(reg | __MCR_SOFT_RST, flexcan->io_base + CAN_HW_REG_MCR);
|
|
mod_timer(&flexcan->timer, HZ / 20);
|
|
}
|
|
|
|
static int flexcan_hw_open(struct flexcan_device *flexcan)
|
|
{
|
|
if (flexcan_hw_reset(flexcan))
|
|
return -EFAULT;
|
|
|
|
flexcan_mcr_setup(flexcan);
|
|
flexcan_ctrl_setup(flexcan);
|
|
|
|
__raw_writel(0, flexcan->io_base + CAN_HW_REG_IMASK2);
|
|
__raw_writel(0, flexcan->io_base + CAN_HW_REG_IMASK1);
|
|
|
|
__raw_writel(0xFFFFFFFF, flexcan->io_base + CAN_HW_REG_IFLAG2);
|
|
__raw_writel(0xFFFFFFFF, flexcan->io_base + CAN_HW_REG_IFLAG1);
|
|
|
|
__raw_writel(0, flexcan->io_base + CAN_HW_REG_ECR);
|
|
return 0;
|
|
}
|
|
|
|
static void flexcan_err_handler(struct net_device *dev)
|
|
{
|
|
struct flexcan_device *flexcan = netdev_priv(dev);
|
|
struct sk_buff *skb;
|
|
struct can_frame *frame;
|
|
unsigned int esr, ecr;
|
|
|
|
esr = __raw_readl(flexcan->io_base + CAN_HW_REG_ESR);
|
|
__raw_writel(esr & __ESR_INTERRUPTS, flexcan->io_base + CAN_HW_REG_ESR);
|
|
|
|
if (esr & __ESR_WAK_INT)
|
|
return;
|
|
|
|
skb = dev_alloc_skb(sizeof(struct can_frame));
|
|
if (!skb) {
|
|
printk(KERN_ERR "%s: allocates skb fail in\n", __func__);
|
|
return;
|
|
}
|
|
frame = (struct can_frame *)skb_put(skb, sizeof(*frame));
|
|
memset(frame, 0, sizeof(*frame));
|
|
frame->can_id = CAN_ERR_FLAG | CAN_ERR_CRTL;
|
|
frame->can_dlc = CAN_ERR_DLC;
|
|
|
|
if (esr & __ESR_TWRN_INT)
|
|
frame->data[1] |= CAN_ERR_CRTL_TX_WARNING;
|
|
|
|
if (esr & __ESR_RWRN_INT)
|
|
frame->data[1] |= CAN_ERR_CRTL_RX_WARNING;
|
|
|
|
if (esr & __ESR_BOFF_INT)
|
|
frame->can_id |= CAN_ERR_BUSOFF;
|
|
|
|
if (esr & __ESR_ERR_INT) {
|
|
if (esr & __ESR_BIT1_ERR)
|
|
frame->data[2] |= CAN_ERR_PROT_BIT1;
|
|
|
|
if (esr & __ESR_BIT0_ERR)
|
|
frame->data[2] |= CAN_ERR_PROT_BIT0;
|
|
|
|
if (esr & __ESR_ACK_ERR)
|
|
frame->can_id |= CAN_ERR_ACK;
|
|
|
|
/*TODO:// if (esr & __ESR_CRC_ERR) */
|
|
|
|
if (esr & __ESR_FRM_ERR)
|
|
frame->data[2] |= CAN_ERR_PROT_FORM;
|
|
|
|
if (esr & __ESR_STF_ERR)
|
|
frame->data[2] |= CAN_ERR_PROT_STUFF;
|
|
|
|
ecr = __raw_readl(flexcan->io_base + CAN_HW_REG_ECR);
|
|
switch ((esr & __ESR_FLT_CONF_MASK) >> __ESR_FLT_CONF_OFF) {
|
|
case 0:
|
|
if (__ECR_TX_ERR_COUNTER(ecr) >= __ECR_ACTIVE_THRESHOLD)
|
|
frame->data[1] |= CAN_ERR_CRTL_TX_WARNING;
|
|
if (__ECR_RX_ERR_COUNTER(ecr) >= __ECR_ACTIVE_THRESHOLD)
|
|
frame->data[1] |= CAN_ERR_CRTL_RX_WARNING;
|
|
break;
|
|
case 1:
|
|
if (__ECR_TX_ERR_COUNTER(ecr) >=
|
|
__ECR_PASSIVE_THRESHOLD)
|
|
frame->data[1] |= CAN_ERR_CRTL_TX_PASSIVE;
|
|
|
|
if (__ECR_RX_ERR_COUNTER(ecr) >=
|
|
__ECR_PASSIVE_THRESHOLD)
|
|
frame->data[1] |= CAN_ERR_CRTL_RX_PASSIVE;
|
|
break;
|
|
default:
|
|
frame->can_id |= CAN_ERR_BUSOFF;
|
|
}
|
|
}
|
|
|
|
if (frame->can_id & CAN_ERR_BUSOFF)
|
|
flexcan_hw_busoff(dev);
|
|
|
|
skb->dev = dev;
|
|
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
|
netif_receive_skb(skb);
|
|
}
|
|
|
|
static irqreturn_t flexcan_irq_handler(int irq, void *data)
|
|
{
|
|
struct net_device *dev = (struct net_device *)data;
|
|
struct flexcan_device *flexcan = dev ? netdev_priv(dev) : NULL;
|
|
unsigned int reg;
|
|
|
|
BUG_ON(!flexcan);
|
|
|
|
reg = __raw_readl(flexcan->io_base + CAN_HW_REG_ESR);
|
|
if (reg & __ESR_INTERRUPTS) {
|
|
flexcan_err_handler(dev);
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
flexcan_mbm_isr(dev);
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
static int flexcan_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
|
{
|
|
struct can_frame *frame = (struct can_frame *)skb->data;
|
|
struct flexcan_device *flexcan = netdev_priv(dev);
|
|
struct net_device_stats *stats = &dev->stats;
|
|
|
|
BUG_ON(!flexcan);
|
|
|
|
if (frame->can_dlc > 8)
|
|
return -EINVAL;
|
|
|
|
if (!flexcan_mbm_xmit(flexcan, frame)) {
|
|
dev_kfree_skb(skb);
|
|
stats->tx_bytes += frame->can_dlc;
|
|
stats->tx_packets++;
|
|
dev->trans_start = jiffies;
|
|
return NETDEV_TX_OK;
|
|
}
|
|
netif_stop_queue(dev);
|
|
return NETDEV_TX_BUSY;
|
|
}
|
|
|
|
static int flexcan_open(struct net_device *dev)
|
|
{
|
|
struct flexcan_device *flexcan;
|
|
struct platform_device *pdev;
|
|
struct flexcan_platform_data *plat_data;
|
|
|
|
flexcan = netdev_priv(dev);
|
|
BUG_ON(!flexcan);
|
|
|
|
pdev = flexcan->dev;
|
|
plat_data = (pdev->dev).platform_data;
|
|
if (plat_data && plat_data->active)
|
|
plat_data->active(pdev->id);
|
|
|
|
if (flexcan->clk)
|
|
if (clk_enable(flexcan->clk))
|
|
goto clk_err;
|
|
|
|
if (flexcan->core_reg)
|
|
if (regulator_enable(flexcan->core_reg))
|
|
goto core_reg_err;
|
|
|
|
if (flexcan->io_reg)
|
|
if (regulator_enable(flexcan->io_reg))
|
|
goto io_reg_err;
|
|
|
|
if (plat_data && plat_data->xcvr_enable)
|
|
plat_data->xcvr_enable(pdev->id, 1);
|
|
|
|
if (request_irq(flexcan->irq, flexcan_irq_handler, IRQF_SAMPLE_RANDOM,
|
|
dev->name, dev))
|
|
goto irq_err;
|
|
|
|
if (flexcan_hw_open(flexcan))
|
|
goto open_err;
|
|
|
|
flexcan_mbm_init(flexcan);
|
|
netif_carrier_on(dev);
|
|
flexcan_hw_start(flexcan);
|
|
return 0;
|
|
open_err:
|
|
free_irq(flexcan->irq, dev);
|
|
irq_err:
|
|
if (plat_data && plat_data->xcvr_enable)
|
|
plat_data->xcvr_enable(pdev->id, 0);
|
|
|
|
if (flexcan->io_reg)
|
|
regulator_disable(flexcan->io_reg);
|
|
io_reg_err:
|
|
if (flexcan->core_reg)
|
|
regulator_disable(flexcan->core_reg);
|
|
core_reg_err:
|
|
if (flexcan->clk)
|
|
clk_disable(flexcan->clk);
|
|
clk_err:
|
|
if (plat_data && plat_data->inactive)
|
|
plat_data->inactive(pdev->id);
|
|
return -ENODEV;
|
|
}
|
|
|
|
static int flexcan_stop(struct net_device *dev)
|
|
{
|
|
struct flexcan_device *flexcan;
|
|
struct platform_device *pdev;
|
|
struct flexcan_platform_data *plat_data;
|
|
|
|
flexcan = netdev_priv(dev);
|
|
|
|
BUG_ON(!flexcan);
|
|
|
|
pdev = flexcan->dev;
|
|
plat_data = (pdev->dev).platform_data;
|
|
|
|
flexcan_hw_stop(flexcan);
|
|
|
|
free_irq(flexcan->irq, dev);
|
|
|
|
if (plat_data && plat_data->xcvr_enable)
|
|
plat_data->xcvr_enable(pdev->id, 0);
|
|
|
|
if (flexcan->io_reg)
|
|
regulator_disable(flexcan->io_reg);
|
|
if (flexcan->core_reg)
|
|
regulator_disable(flexcan->core_reg);
|
|
if (flexcan->clk)
|
|
clk_disable(flexcan->clk);
|
|
if (plat_data && plat_data->inactive)
|
|
plat_data->inactive(pdev->id);
|
|
return 0;
|
|
}
|
|
|
|
static struct net_device_ops flexcan_netdev_ops = {
|
|
.ndo_open = flexcan_open,
|
|
.ndo_stop = flexcan_stop,
|
|
.ndo_start_xmit = flexcan_start_xmit,
|
|
};
|
|
|
|
static void flexcan_setup(struct net_device *dev)
|
|
{
|
|
dev->type = ARPHRD_CAN;
|
|
dev->mtu = sizeof(struct can_frame);
|
|
dev->hard_header_len = 0;
|
|
dev->addr_len = 0;
|
|
dev->tx_queue_len = FLEXCAN_MAX_MB;
|
|
dev->flags = IFF_NOARP;
|
|
dev->features = NETIF_F_NO_CSUM;
|
|
|
|
dev->netdev_ops = &flexcan_netdev_ops;
|
|
}
|
|
|
|
static int flexcan_probe(struct platform_device *pdev)
|
|
{
|
|
struct net_device *net;
|
|
net = flexcan_device_alloc(pdev, flexcan_setup);
|
|
if (!net)
|
|
return -ENOMEM;
|
|
|
|
if (register_netdev(net)) {
|
|
flexcan_device_free(pdev);
|
|
return -ENODEV;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int flexcan_remove(struct platform_device *pdev)
|
|
{
|
|
flexcan_device_free(pdev);
|
|
return 0;
|
|
}
|
|
|
|
static int flexcan_suspend(struct platform_device *pdev, pm_message_t state)
|
|
{
|
|
struct net_device *net;
|
|
struct flexcan_device *flexcan;
|
|
struct flexcan_platform_data *plat_data;
|
|
net = (struct net_device *)dev_get_drvdata(&pdev->dev);
|
|
flexcan = netdev_priv(net);
|
|
|
|
BUG_ON(!flexcan);
|
|
|
|
if (!(net->flags & IFF_UP))
|
|
return 0;
|
|
if (flexcan->wakeup)
|
|
set_irq_wake(flexcan->irq, 1);
|
|
else {
|
|
plat_data = (pdev->dev).platform_data;
|
|
|
|
if (plat_data && plat_data->xcvr_enable)
|
|
plat_data->xcvr_enable(pdev->id, 0);
|
|
|
|
if (flexcan->io_reg)
|
|
regulator_disable(flexcan->io_reg);
|
|
if (flexcan->core_reg)
|
|
regulator_disable(flexcan->core_reg);
|
|
if (flexcan->clk)
|
|
clk_disable(flexcan->clk);
|
|
if (plat_data && plat_data->inactive)
|
|
plat_data->inactive(pdev->id);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int flexcan_resume(struct platform_device *pdev)
|
|
{
|
|
struct net_device *net;
|
|
struct flexcan_device *flexcan;
|
|
struct flexcan_platform_data *plat_data;
|
|
net = (struct net_device *)dev_get_drvdata(&pdev->dev);
|
|
flexcan = netdev_priv(net);
|
|
|
|
BUG_ON(!flexcan);
|
|
|
|
if (!(net->flags & IFF_UP))
|
|
return 0;
|
|
|
|
if (flexcan->wakeup)
|
|
set_irq_wake(flexcan->irq, 0);
|
|
else {
|
|
plat_data = (pdev->dev).platform_data;
|
|
if (plat_data && plat_data->active)
|
|
plat_data->active(pdev->id);
|
|
|
|
if (flexcan->clk) {
|
|
if (clk_enable(flexcan->clk))
|
|
printk(KERN_ERR "%s:enable clock fail\n",
|
|
__func__);
|
|
}
|
|
|
|
if (flexcan->core_reg) {
|
|
if (regulator_enable(flexcan->core_reg))
|
|
printk(KERN_ERR "%s:enable core voltage\n",
|
|
__func__);
|
|
}
|
|
if (flexcan->io_reg) {
|
|
if (regulator_enable(flexcan->io_reg))
|
|
printk(KERN_ERR "%s:enable io voltage\n",
|
|
__func__);
|
|
}
|
|
|
|
if (plat_data && plat_data->xcvr_enable)
|
|
plat_data->xcvr_enable(pdev->id, 1);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static struct platform_driver flexcan_driver = {
|
|
.driver = {
|
|
.name = FLEXCAN_DEVICE_NAME,
|
|
},
|
|
.probe = flexcan_probe,
|
|
.remove = flexcan_remove,
|
|
.suspend = flexcan_suspend,
|
|
.resume = flexcan_resume,
|
|
};
|
|
|
|
static __init int flexcan_init(void)
|
|
{
|
|
pr_info("Freescale FlexCAN Driver \n");
|
|
return platform_driver_register(&flexcan_driver);
|
|
}
|
|
|
|
static __exit void flexcan_exit(void)
|
|
{
|
|
return platform_driver_unregister(&flexcan_driver);
|
|
}
|
|
|
|
module_init(flexcan_init);
|
|
module_exit(flexcan_exit);
|
|
|
|
MODULE_LICENSE("GPL");
|