*
* Some SOCs do not have the RX_WARN & TX_WARN interrupt line connected.
*/
-#define FLEXCAN_HAS_V10_FEATURES BIT(1) /* For core version >= 10 */
-#define FLEXCAN_HAS_BROKEN_ERR_STATE BIT(2) /* [TR]WRN_INT not connected */
-#define FLEXCAN_HAS_MECR_FEATURES BIT(3) /* Memory error detection */
+#define FLEXCAN_QUIRK_BROKEN_ERR_STATE BIT(1) /* [TR]WRN_INT not connected */
+#define FLEXCAN_QUIRK_DISABLE_RXFG BIT(2) /* Disable RX FIFO Global mask */
+#define FLEXCAN_QUIRK_DISABLE_MECR BIT(3) /* Disble Memory error detection */
/* Structure of the message buffer */
struct flexcan_mb {
u32 rxfgmask; /* 0x48 */
u32 rxfir; /* 0x4c */
u32 _reserved3[12]; /* 0x50 */
- struct flexcan_mb cantxfg[64]; /* 0x80 */
+ struct flexcan_mb mb[64]; /* 0x80 */
/* FIFO-mode:
* MB
* 0x080...0x08f 0 RX message buffer
};
struct flexcan_devtype_data {
- u32 features; /* hardware controller features */
+ u32 quirks; /* quirks needed for different IP cores */
};
struct flexcan_priv {
struct can_priv can;
struct napi_struct napi;
- void __iomem *base;
+ struct flexcan_regs __iomem *regs;
u32 reg_esr;
u32 reg_ctrl_default;
};
static struct flexcan_devtype_data fsl_p1010_devtype_data = {
- .features = FLEXCAN_HAS_BROKEN_ERR_STATE,
+ .quirks = FLEXCAN_QUIRK_BROKEN_ERR_STATE,
};
static struct flexcan_devtype_data fsl_imx28_devtype_data;
static struct flexcan_devtype_data fsl_imx6q_devtype_data = {
- .features = FLEXCAN_HAS_V10_FEATURES,
+ .quirks = FLEXCAN_QUIRK_DISABLE_RXFG,
};
static struct flexcan_devtype_data fsl_vf610_devtype_data = {
- .features = FLEXCAN_HAS_V10_FEATURES | FLEXCAN_HAS_MECR_FEATURES,
+ .quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_DISABLE_MECR,
};
static const struct can_bittiming_const flexcan_bittiming_const = {
static int flexcan_chip_enable(struct flexcan_priv *priv)
{
- struct flexcan_regs __iomem *regs = priv->base;
+ struct flexcan_regs __iomem *regs = priv->regs;
unsigned int timeout = FLEXCAN_TIMEOUT_US / 10;
u32 reg;
static int flexcan_chip_disable(struct flexcan_priv *priv)
{
- struct flexcan_regs __iomem *regs = priv->base;
+ struct flexcan_regs __iomem *regs = priv->regs;
unsigned int timeout = FLEXCAN_TIMEOUT_US / 10;
u32 reg;
static int flexcan_chip_freeze(struct flexcan_priv *priv)
{
- struct flexcan_regs __iomem *regs = priv->base;
+ struct flexcan_regs __iomem *regs = priv->regs;
unsigned int timeout = 1000 * 1000 * 10 / priv->can.bittiming.bitrate;
u32 reg;
static int flexcan_chip_unfreeze(struct flexcan_priv *priv)
{
- struct flexcan_regs __iomem *regs = priv->base;
+ struct flexcan_regs __iomem *regs = priv->regs;
unsigned int timeout = FLEXCAN_TIMEOUT_US / 10;
u32 reg;
static int flexcan_chip_softreset(struct flexcan_priv *priv)
{
- struct flexcan_regs __iomem *regs = priv->base;
+ struct flexcan_regs __iomem *regs = priv->regs;
unsigned int timeout = FLEXCAN_TIMEOUT_US / 10;
flexcan_write(FLEXCAN_MCR_SOFTRST, ®s->mcr);
struct can_berr_counter *bec)
{
const struct flexcan_priv *priv = netdev_priv(dev);
- struct flexcan_regs __iomem *regs = priv->base;
+ struct flexcan_regs __iomem *regs = priv->regs;
u32 reg = flexcan_read(®s->ecr);
bec->txerr = (reg >> 0) & 0xff;
static int flexcan_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
const struct flexcan_priv *priv = netdev_priv(dev);
- struct flexcan_regs __iomem *regs = priv->base;
+ struct flexcan_regs __iomem *regs = priv->regs;
struct can_frame *cf = (struct can_frame *)skb->data;
u32 can_id;
u32 data;
if (cf->can_dlc > 0) {
data = be32_to_cpup((__be32 *)&cf->data[0]);
- flexcan_write(data, ®s->cantxfg[FLEXCAN_TX_BUF_ID].data[0]);
+ flexcan_write(data, ®s->mb[FLEXCAN_TX_BUF_ID].data[0]);
}
if (cf->can_dlc > 3) {
data = be32_to_cpup((__be32 *)&cf->data[4]);
- flexcan_write(data, ®s->cantxfg[FLEXCAN_TX_BUF_ID].data[1]);
+ flexcan_write(data, ®s->mb[FLEXCAN_TX_BUF_ID].data[1]);
}
can_put_echo_skb(skb, dev, 0);
- flexcan_write(can_id, ®s->cantxfg[FLEXCAN_TX_BUF_ID].can_id);
- flexcan_write(ctrl, ®s->cantxfg[FLEXCAN_TX_BUF_ID].can_ctrl);
+ flexcan_write(can_id, ®s->mb[FLEXCAN_TX_BUF_ID].can_id);
+ flexcan_write(ctrl, ®s->mb[FLEXCAN_TX_BUF_ID].can_ctrl);
/* Errata ERR005829 step8:
* Write twice INACTIVE(0x8) code to first MB.
*/
flexcan_write(FLEXCAN_MB_CODE_TX_INACTIVE,
- ®s->cantxfg[FLEXCAN_TX_BUF_RESERVED].can_ctrl);
+ ®s->mb[FLEXCAN_TX_BUF_RESERVED].can_ctrl);
flexcan_write(FLEXCAN_MB_CODE_TX_INACTIVE,
- ®s->cantxfg[FLEXCAN_TX_BUF_RESERVED].can_ctrl);
+ ®s->mb[FLEXCAN_TX_BUF_RESERVED].can_ctrl);
return NETDEV_TX_OK;
}
struct can_frame *cf)
{
const struct flexcan_priv *priv = netdev_priv(dev);
- struct flexcan_regs __iomem *regs = priv->base;
- struct flexcan_mb __iomem *mb = ®s->cantxfg[0];
+ struct flexcan_regs __iomem *regs = priv->regs;
+ struct flexcan_mb __iomem *mb = ®s->mb[0];
u32 reg_ctrl, reg_id;
reg_ctrl = flexcan_read(&mb->can_ctrl);
{
struct net_device *dev = napi->dev;
const struct flexcan_priv *priv = netdev_priv(dev);
- struct flexcan_regs __iomem *regs = priv->base;
+ struct flexcan_regs __iomem *regs = priv->regs;
u32 reg_iflag1, reg_esr;
int work_done = 0;
struct net_device *dev = dev_id;
struct net_device_stats *stats = &dev->stats;
struct flexcan_priv *priv = netdev_priv(dev);
- struct flexcan_regs __iomem *regs = priv->base;
+ struct flexcan_regs __iomem *regs = priv->regs;
u32 reg_iflag1, reg_esr;
reg_iflag1 = flexcan_read(®s->iflag1);
/* after sending a RTR frame MB is in RX mode */
flexcan_write(FLEXCAN_MB_CODE_TX_INACTIVE,
- ®s->cantxfg[FLEXCAN_TX_BUF_ID].can_ctrl);
+ ®s->mb[FLEXCAN_TX_BUF_ID].can_ctrl);
flexcan_write((1 << FLEXCAN_TX_BUF_ID), ®s->iflag1);
netif_wake_queue(dev);
}
{
const struct flexcan_priv *priv = netdev_priv(dev);
const struct can_bittiming *bt = &priv->can.bittiming;
- struct flexcan_regs __iomem *regs = priv->base;
+ struct flexcan_regs __iomem *regs = priv->regs;
u32 reg;
reg = flexcan_read(®s->ctrl);
static int flexcan_chip_start(struct net_device *dev)
{
struct flexcan_priv *priv = netdev_priv(dev);
- struct flexcan_regs __iomem *regs = priv->base;
+ struct flexcan_regs __iomem *regs = priv->regs;
u32 reg_mcr, reg_ctrl, reg_ctrl2, reg_mecr;
int err, i;
* halt now
* only supervisor access
* enable warning int
- * choose format C
* disable local echo
+ * choose format C
+ * set max mailbox number
*/
reg_mcr = flexcan_read(®s->mcr);
reg_mcr &= ~FLEXCAN_MCR_MAXMB(0xff);
reg_mcr |= FLEXCAN_MCR_FRZ | FLEXCAN_MCR_FEN | FLEXCAN_MCR_HALT |
- FLEXCAN_MCR_SUPV | FLEXCAN_MCR_WRN_EN |
- FLEXCAN_MCR_IDAM_C | FLEXCAN_MCR_SRX_DIS |
- FLEXCAN_MCR_MAXMB(FLEXCAN_TX_BUF_ID);
+ FLEXCAN_MCR_SUPV | FLEXCAN_MCR_WRN_EN | FLEXCAN_MCR_SRX_DIS |
+ FLEXCAN_MCR_IDAM_C | FLEXCAN_MCR_MAXMB(FLEXCAN_TX_BUF_ID);
netdev_dbg(dev, "%s: writing mcr=0x%08x", __func__, reg_mcr);
flexcan_write(reg_mcr, ®s->mcr);
* on most Flexcan cores, too. Otherwise we don't get
* any error warning or passive interrupts.
*/
- if (priv->devtype_data->features & FLEXCAN_HAS_BROKEN_ERR_STATE ||
+ if (priv->devtype_data->quirks & FLEXCAN_QUIRK_BROKEN_ERR_STATE ||
priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING)
reg_ctrl |= FLEXCAN_CTRL_ERR_MSK;
else
/* save for later use */
priv->reg_ctrl_default = reg_ctrl;
+ /* leave interrupts disabled for now */
+ reg_ctrl &= ~FLEXCAN_CTRL_ERR_ALL;
netdev_dbg(dev, "%s: writing ctrl=0x%08x", __func__, reg_ctrl);
flexcan_write(reg_ctrl, ®s->ctrl);
/* clear and invalidate all mailboxes first */
- for (i = FLEXCAN_TX_BUF_ID; i < ARRAY_SIZE(regs->cantxfg); i++) {
+ for (i = FLEXCAN_TX_BUF_ID; i < ARRAY_SIZE(regs->mb); i++) {
flexcan_write(FLEXCAN_MB_CODE_RX_INACTIVE,
- ®s->cantxfg[i].can_ctrl);
+ ®s->mb[i].can_ctrl);
}
/* Errata ERR005829: mark first TX mailbox as INACTIVE */
flexcan_write(FLEXCAN_MB_CODE_TX_INACTIVE,
- ®s->cantxfg[FLEXCAN_TX_BUF_RESERVED].can_ctrl);
+ ®s->mb[FLEXCAN_TX_BUF_RESERVED].can_ctrl);
/* mark TX mailbox as INACTIVE */
flexcan_write(FLEXCAN_MB_CODE_TX_INACTIVE,
- ®s->cantxfg[FLEXCAN_TX_BUF_ID].can_ctrl);
+ ®s->mb[FLEXCAN_TX_BUF_ID].can_ctrl);
/* acceptance mask/acceptance code (accept everything) */
flexcan_write(0x0, ®s->rxgmask);
flexcan_write(0x0, ®s->rx14mask);
flexcan_write(0x0, ®s->rx15mask);
- if (priv->devtype_data->features & FLEXCAN_HAS_V10_FEATURES)
+ if (priv->devtype_data->quirks & FLEXCAN_QUIRK_DISABLE_RXFG)
flexcan_write(0x0, ®s->rxfgmask);
/* On Vybrid, disable memory error detection interrupts
* false positive memory errors and put the device in
* freeze mode.
*/
- if (priv->devtype_data->features & FLEXCAN_HAS_MECR_FEATURES) {
+ if (priv->devtype_data->quirks & FLEXCAN_QUIRK_DISABLE_MECR) {
/* Follow the protocol as described in "Detection
* and Correction of Memory Errors" to write to
* MECR register
priv->can.state = CAN_STATE_ERROR_ACTIVE;
- /* enable FIFO interrupts */
+ /* enable interrupts atomically */
+ disable_irq(dev->irq);
+ flexcan_write(priv->reg_ctrl_default, ®s->ctrl);
flexcan_write(FLEXCAN_IFLAG_DEFAULT, ®s->imask1);
+ enable_irq(dev->irq);
/* print chip status */
netdev_dbg(dev, "%s: reading mcr=0x%08x ctrl=0x%08x\n", __func__,
static void flexcan_chip_stop(struct net_device *dev)
{
struct flexcan_priv *priv = netdev_priv(dev);
- struct flexcan_regs __iomem *regs = priv->base;
+ struct flexcan_regs __iomem *regs = priv->regs;
/* freeze + disable module */
flexcan_chip_freeze(priv);
static int register_flexcandev(struct net_device *dev)
{
struct flexcan_priv *priv = netdev_priv(dev);
- struct flexcan_regs __iomem *regs = priv->base;
+ struct flexcan_regs __iomem *regs = priv->regs;
u32 reg, err;
err = clk_prepare_enable(priv->clk_ipg);
struct regulator *reg_xceiver;
struct resource *mem;
struct clk *clk_ipg = NULL, *clk_per = NULL;
- void __iomem *base;
+ struct flexcan_regs __iomem *regs;
int err, irq;
u32 clock_freq = 0;
if (irq <= 0)
return -ENODEV;
- base = devm_ioremap_resource(&pdev->dev, mem);
- if (IS_ERR(base))
- return PTR_ERR(base);
+ regs = devm_ioremap_resource(&pdev->dev, mem);
+ if (IS_ERR(regs))
+ return PTR_ERR(regs);
of_id = of_match_device(flexcan_of_match, &pdev->dev);
if (of_id) {
priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK |
CAN_CTRLMODE_LISTENONLY | CAN_CTRLMODE_3_SAMPLES |
CAN_CTRLMODE_BERR_REPORTING;
- priv->base = base;
+ priv->regs = regs;
priv->clk_ipg = clk_ipg;
priv->clk_per = clk_per;
priv->pdata = dev_get_platdata(&pdev->dev);
devm_can_led_init(dev);
dev_info(&pdev->dev, "device registered (reg_base=%p, irq=%d)\n",
- priv->base, dev->irq);
+ priv->regs, dev->irq);
return 0;