Lines Matching +full:sun7i +full:- +full:a20 +full:- +full:out +full:- +full:clk

2  * sun4i_can.c - CAN bus controller driver for Allwinner SUN4I&SUN7I based SoCs
11 * Copyright (C) 2002-2007 Volkswagen Group Electronic Research
44 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
54 #include <linux/clk.h>
206 * struct sun4ican_quirks - Differences between SoC variants.
219 struct clk *clk; member
241 spin_lock_irqsave(&priv->cmdreg_lock, flags); in sun4i_can_write_cmdreg()
242 writel(val, priv->base + SUN4I_REG_CMD_ADDR); in sun4i_can_write_cmdreg()
243 spin_unlock_irqrestore(&priv->cmdreg_lock, flags); in sun4i_can_write_cmdreg()
253 mod_reg_val = readl(priv->base + SUN4I_REG_MSEL_ADDR); in set_normal_mode()
255 writel(mod_reg_val, priv->base + SUN4I_REG_MSEL_ADDR); in set_normal_mode()
256 } while (retry-- && (mod_reg_val & SUN4I_MSEL_RESET_MODE)); in set_normal_mode()
258 if (readl(priv->base + SUN4I_REG_MSEL_ADDR) & SUN4I_MSEL_RESET_MODE) { in set_normal_mode()
261 return -ETIMEDOUT; in set_normal_mode()
274 mod_reg_val = readl(priv->base + SUN4I_REG_MSEL_ADDR); in set_reset_mode()
276 writel(mod_reg_val, priv->base + SUN4I_REG_MSEL_ADDR); in set_reset_mode()
277 } while (retry-- && !(mod_reg_val & SUN4I_MSEL_RESET_MODE)); in set_reset_mode()
279 if (!(readl(priv->base + SUN4I_REG_MSEL_ADDR) & in set_reset_mode()
282 return -ETIMEDOUT; in set_reset_mode()
292 struct can_bittiming *bt = &priv->can.bittiming; in sun4ican_set_bittiming()
295 cfg = ((bt->brp - 1) & 0x3FF) | in sun4ican_set_bittiming()
296 (((bt->sjw - 1) & 0x3) << 14) | in sun4ican_set_bittiming()
297 (((bt->prop_seg + bt->phase_seg1 - 1) & 0xf) << 16) | in sun4ican_set_bittiming()
298 (((bt->phase_seg2 - 1) & 0x7) << 20); in sun4ican_set_bittiming()
299 if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) in sun4ican_set_bittiming()
303 writel(cfg, priv->base + SUN4I_REG_BTIME_ADDR); in sun4ican_set_bittiming()
315 err = clk_prepare_enable(priv->clk); in sun4ican_get_berr_counter()
321 errors = readl(priv->base + SUN4I_REG_ERRC_ADDR); in sun4ican_get_berr_counter()
323 bec->txerr = errors & 0xFF; in sun4ican_get_berr_counter()
324 bec->rxerr = (errors >> 16) & 0xFF; in sun4ican_get_berr_counter()
326 clk_disable_unprepare(priv->clk); in sun4ican_get_berr_counter()
344 /* set filters - we accept all */ in sun4i_can_start()
345 writel(0x00000000, priv->base + SUN4I_REG_ACPC_ADDR + priv->acp_offset); in sun4i_can_start()
346 writel(0xFFFFFFFF, priv->base + SUN4I_REG_ACPM_ADDR + priv->acp_offset); in sun4i_can_start()
349 writel(0, priv->base + SUN4I_REG_ERRC_ADDR); in sun4i_can_start()
352 if (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) in sun4i_can_start()
353 writel(0xFF, priv->base + SUN4I_REG_INTEN_ADDR); in sun4i_can_start()
356 priv->base + SUN4I_REG_INTEN_ADDR); in sun4i_can_start()
359 mod_reg_val = readl(priv->base + SUN4I_REG_MSEL_ADDR); in sun4i_can_start()
360 if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) in sun4i_can_start()
362 else if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) in sun4i_can_start()
364 writel(mod_reg_val, priv->base + SUN4I_REG_MSEL_ADDR); in sun4i_can_start()
377 priv->can.state = CAN_STATE_ERROR_ACTIVE; in sun4i_can_start()
387 priv->can.state = CAN_STATE_STOPPED; in sun4i_can_stop()
396 writel(0, priv->base + SUN4I_REG_INTEN_ADDR); in sun4i_can_stop()
417 return -EOPNOTSUPP; in sun4ican_set_mode()
430 struct can_frame *cf = (struct can_frame *)skb->data; in sun4ican_start_xmit()
441 id = cf->can_id; in sun4ican_start_xmit()
442 dlc = cf->len; in sun4ican_start_xmit()
451 writel((id >> 21) & 0xFF, priv->base + SUN4I_REG_BUF1_ADDR); in sun4ican_start_xmit()
452 writel((id >> 13) & 0xFF, priv->base + SUN4I_REG_BUF2_ADDR); in sun4ican_start_xmit()
453 writel((id >> 5) & 0xFF, priv->base + SUN4I_REG_BUF3_ADDR); in sun4ican_start_xmit()
454 writel((id << 3) & 0xF8, priv->base + SUN4I_REG_BUF4_ADDR); in sun4ican_start_xmit()
457 writel((id >> 3) & 0xFF, priv->base + SUN4I_REG_BUF1_ADDR); in sun4ican_start_xmit()
458 writel((id << 5) & 0xE0, priv->base + SUN4I_REG_BUF2_ADDR); in sun4ican_start_xmit()
462 writel(cf->data[i], priv->base + (dreg + i * 4)); in sun4ican_start_xmit()
464 writel(msg_flag_n, priv->base + SUN4I_REG_BUF0_ADDR); in sun4ican_start_xmit()
468 if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) in sun4ican_start_xmit()
479 struct net_device_stats *stats = &dev->stats; in sun4i_can_rx()
492 fi = readl(priv->base + SUN4I_REG_BUF0_ADDR); in sun4i_can_rx()
493 cf->len = can_cc_dlc2len(fi & 0x0F); in sun4i_can_rx()
496 id = (readl(priv->base + SUN4I_REG_BUF1_ADDR) << 21) | in sun4i_can_rx()
497 (readl(priv->base + SUN4I_REG_BUF2_ADDR) << 13) | in sun4i_can_rx()
498 (readl(priv->base + SUN4I_REG_BUF3_ADDR) << 5) | in sun4i_can_rx()
499 ((readl(priv->base + SUN4I_REG_BUF4_ADDR) >> 3) & 0x1f); in sun4i_can_rx()
503 id = (readl(priv->base + SUN4I_REG_BUF1_ADDR) << 3) | in sun4i_can_rx()
504 ((readl(priv->base + SUN4I_REG_BUF2_ADDR) >> 5) & 0x7); in sun4i_can_rx()
511 for (i = 0; i < cf->len; i++) in sun4i_can_rx()
512 cf->data[i] = readl(priv->base + dreg + i * 4); in sun4i_can_rx()
514 stats->rx_bytes += cf->len; in sun4i_can_rx()
516 stats->rx_packets++; in sun4i_can_rx()
518 cf->can_id = id; in sun4i_can_rx()
528 struct net_device_stats *stats = &dev->stats; in sun4i_can_err()
531 enum can_state state = priv->can.state; in sun4i_can_err()
539 errc = readl(priv->base + SUN4I_REG_ERRC_ADDR); in sun4i_can_err()
547 cf->can_id |= CAN_ERR_CRTL; in sun4i_can_err()
548 cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; in sun4i_can_err()
550 stats->rx_over_errors++; in sun4i_can_err()
551 stats->rx_errors++; in sun4i_can_err()
574 cf->can_id |= CAN_ERR_CNT; in sun4i_can_err()
575 cf->data[6] = txerr; in sun4i_can_err()
576 cf->data[7] = rxerr; in sun4i_can_err()
581 priv->can.can_stats.bus_error++; in sun4i_can_err()
582 stats->rx_errors++; in sun4i_can_err()
585 ecc = readl(priv->base + SUN4I_REG_STA_ADDR); in sun4i_can_err()
587 cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; in sun4i_can_err()
591 cf->data[2] |= CAN_ERR_PROT_BIT; in sun4i_can_err()
594 cf->data[2] |= CAN_ERR_PROT_FORM; in sun4i_can_err()
597 cf->data[2] |= CAN_ERR_PROT_STUFF; in sun4i_can_err()
600 cf->data[3] = (ecc & SUN4I_STA_ERR_SEG_CODE) in sun4i_can_err()
606 cf->data[2] |= CAN_ERR_PROT_TX; in sun4i_can_err()
620 alc = readl(priv->base + SUN4I_REG_STA_ADDR); in sun4i_can_err()
621 priv->can.can_stats.arbitration_lost++; in sun4i_can_err()
623 cf->can_id |= CAN_ERR_LOSTARB; in sun4i_can_err()
624 cf->data[0] = (alc >> 8) & 0x1f; in sun4i_can_err()
628 if (state != priv->can.state) { in sun4i_can_err()
635 priv->can.state = state; in sun4i_can_err()
643 return -ENOMEM; in sun4i_can_err()
652 struct net_device_stats *stats = &dev->stats; in sun4i_can_interrupt()
656 while ((isrc = readl(priv->base + SUN4I_REG_INT_ADDR)) && in sun4i_can_interrupt()
659 status = readl(priv->base + SUN4I_REG_STA_ADDR); in sun4i_can_interrupt()
666 stats->tx_bytes += can_get_echo_skb(dev, 0, NULL); in sun4i_can_interrupt()
667 stats->tx_packets++; in sun4i_can_interrupt()
672 /* receive interrupt - don't read if overrun occurred */ in sun4i_can_interrupt()
676 status = readl(priv->base + SUN4I_REG_STA_ADDR); in sun4i_can_interrupt()
684 netdev_err(dev, "can't allocate buffer - clearing pending interrupts\n"); in sun4i_can_interrupt()
687 writel(isrc, priv->base + SUN4I_REG_INT_ADDR); in sun4i_can_interrupt()
688 readl(priv->base + SUN4I_REG_INT_ADDR); in sun4i_can_interrupt()
707 err = request_irq(dev->irq, sun4i_can_interrupt, 0, dev->name, dev); in sun4ican_open()
714 err = reset_control_deassert(priv->reset); in sun4ican_open()
721 err = clk_prepare_enable(priv->clk); in sun4ican_open()
738 clk_disable_unprepare(priv->clk); in sun4ican_open()
740 reset_control_assert(priv->reset); in sun4ican_open()
742 free_irq(dev->irq, dev); in sun4ican_open()
754 clk_disable_unprepare(priv->clk); in sun4ican_close()
755 reset_control_assert(priv->reset); in sun4ican_close()
757 free_irq(dev->irq, dev); in sun4ican_close()
785 .acp_offset = (SUN4I_REG_ACPC_ADDR_D1 - SUN4I_REG_ACPC_ADDR),
790 .compatible = "allwinner,sun4i-a10-can",
793 .compatible = "allwinner,sun7i-a20-can",
796 .compatible = "allwinner,sun8i-r40-can",
799 .compatible = "allwinner,sun20i-d1-can",
818 struct device_node *np = pdev->dev.of_node; in sun4ican_probe()
819 struct clk *clk; in sun4ican_probe() local
827 quirks = of_device_get_match_data(&pdev->dev); in sun4ican_probe()
829 dev_err(&pdev->dev, "failed to determine the quirks to use\n"); in sun4ican_probe()
830 err = -ENODEV; in sun4ican_probe()
834 if (quirks->has_reset) { in sun4ican_probe()
835 reset = devm_reset_control_get_exclusive(&pdev->dev, NULL); in sun4ican_probe()
837 dev_err(&pdev->dev, "unable to request reset\n"); in sun4ican_probe()
843 clk = of_clk_get(np, 0); in sun4ican_probe()
844 if (IS_ERR(clk)) { in sun4ican_probe()
845 dev_err(&pdev->dev, "unable to request clock\n"); in sun4ican_probe()
846 err = -ENODEV; in sun4ican_probe()
852 err = -ENODEV; in sun4ican_probe()
864 dev_err(&pdev->dev, in sun4ican_probe()
866 err = -ENOMEM; in sun4ican_probe()
870 dev->netdev_ops = &sun4ican_netdev_ops; in sun4ican_probe()
871 dev->ethtool_ops = &sun4ican_ethtool_ops; in sun4ican_probe()
872 dev->irq = irq; in sun4ican_probe()
873 dev->flags |= IFF_ECHO; in sun4ican_probe()
876 priv->can.clock.freq = clk_get_rate(clk); in sun4ican_probe()
877 priv->can.bittiming_const = &sun4ican_bittiming_const; in sun4ican_probe()
878 priv->can.do_set_mode = sun4ican_set_mode; in sun4ican_probe()
879 priv->can.do_get_berr_counter = sun4ican_get_berr_counter; in sun4ican_probe()
880 priv->can.ctrlmode_supported = CAN_CTRLMODE_BERR_REPORTING | in sun4ican_probe()
884 priv->base = addr; in sun4ican_probe()
885 priv->clk = clk; in sun4ican_probe()
886 priv->reset = reset; in sun4ican_probe()
887 priv->acp_offset = quirks->acp_offset; in sun4ican_probe()
888 spin_lock_init(&priv->cmdreg_lock); in sun4ican_probe()
891 SET_NETDEV_DEV(dev, &pdev->dev); in sun4ican_probe()
895 dev_err(&pdev->dev, "registering %s failed (err=%d)\n", in sun4ican_probe()
900 dev_info(&pdev->dev, "device registered (base=%p, irq=%d)\n", in sun4ican_probe()
901 priv->base, dev->irq); in sun4ican_probe()
923 MODULE_AUTHOR("Gerhard Bertelsmann <info@gerhard-bertelsmann.de>");
925 MODULE_DESCRIPTION("CAN driver for Allwinner SoCs (A10/A20/D1)");