18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 1999 - 2010 Intel Corporation. 48c2ecf20Sopenharmony_ci * Copyright (C) 2010 LAPIS SEMICONDUCTOR CO., LTD. 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 88c2ecf20Sopenharmony_ci#include <linux/delay.h> 98c2ecf20Sopenharmony_ci#include <linux/io.h> 108c2ecf20Sopenharmony_ci#include <linux/module.h> 118c2ecf20Sopenharmony_ci#include <linux/sched.h> 128c2ecf20Sopenharmony_ci#include <linux/pci.h> 138c2ecf20Sopenharmony_ci#include <linux/kernel.h> 148c2ecf20Sopenharmony_ci#include <linux/types.h> 158c2ecf20Sopenharmony_ci#include <linux/errno.h> 168c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 178c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 188c2ecf20Sopenharmony_ci#include <linux/can.h> 198c2ecf20Sopenharmony_ci#include <linux/can/dev.h> 208c2ecf20Sopenharmony_ci#include <linux/can/error.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#define PCH_CTRL_INIT BIT(0) /* The INIT bit of CANCONT register. */ 238c2ecf20Sopenharmony_ci#define PCH_CTRL_IE BIT(1) /* The IE bit of CAN control register */ 248c2ecf20Sopenharmony_ci#define PCH_CTRL_IE_SIE_EIE (BIT(3) | BIT(2) | BIT(1)) 258c2ecf20Sopenharmony_ci#define PCH_CTRL_CCE BIT(6) 268c2ecf20Sopenharmony_ci#define PCH_CTRL_OPT BIT(7) /* The OPT bit of CANCONT register. */ 278c2ecf20Sopenharmony_ci#define PCH_OPT_SILENT BIT(3) /* The Silent bit of CANOPT reg. */ 288c2ecf20Sopenharmony_ci#define PCH_OPT_LBACK BIT(4) /* The LoopBack bit of CANOPT reg. */ 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#define PCH_CMASK_RX_TX_SET 0x00f3 318c2ecf20Sopenharmony_ci#define PCH_CMASK_RX_TX_GET 0x0073 328c2ecf20Sopenharmony_ci#define PCH_CMASK_ALL 0xff 338c2ecf20Sopenharmony_ci#define PCH_CMASK_NEWDAT BIT(2) 348c2ecf20Sopenharmony_ci#define PCH_CMASK_CLRINTPND BIT(3) 358c2ecf20Sopenharmony_ci#define PCH_CMASK_CTRL BIT(4) 368c2ecf20Sopenharmony_ci#define PCH_CMASK_ARB BIT(5) 378c2ecf20Sopenharmony_ci#define PCH_CMASK_MASK BIT(6) 388c2ecf20Sopenharmony_ci#define PCH_CMASK_RDWR BIT(7) 398c2ecf20Sopenharmony_ci#define PCH_IF_MCONT_NEWDAT BIT(15) 408c2ecf20Sopenharmony_ci#define PCH_IF_MCONT_MSGLOST BIT(14) 418c2ecf20Sopenharmony_ci#define PCH_IF_MCONT_INTPND BIT(13) 428c2ecf20Sopenharmony_ci#define PCH_IF_MCONT_UMASK BIT(12) 438c2ecf20Sopenharmony_ci#define PCH_IF_MCONT_TXIE BIT(11) 448c2ecf20Sopenharmony_ci#define PCH_IF_MCONT_RXIE BIT(10) 458c2ecf20Sopenharmony_ci#define PCH_IF_MCONT_RMTEN BIT(9) 468c2ecf20Sopenharmony_ci#define PCH_IF_MCONT_TXRQXT BIT(8) 478c2ecf20Sopenharmony_ci#define PCH_IF_MCONT_EOB BIT(7) 488c2ecf20Sopenharmony_ci#define PCH_IF_MCONT_DLC (BIT(0) | BIT(1) | BIT(2) | BIT(3)) 498c2ecf20Sopenharmony_ci#define PCH_MASK2_MDIR_MXTD (BIT(14) | BIT(15)) 508c2ecf20Sopenharmony_ci#define PCH_ID2_DIR BIT(13) 518c2ecf20Sopenharmony_ci#define PCH_ID2_XTD BIT(14) 528c2ecf20Sopenharmony_ci#define PCH_ID_MSGVAL BIT(15) 538c2ecf20Sopenharmony_ci#define PCH_IF_CREQ_BUSY BIT(15) 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci#define PCH_STATUS_INT 0x8000 568c2ecf20Sopenharmony_ci#define PCH_RP 0x00008000 578c2ecf20Sopenharmony_ci#define PCH_REC 0x00007f00 588c2ecf20Sopenharmony_ci#define PCH_TEC 0x000000ff 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci#define PCH_TX_OK BIT(3) 618c2ecf20Sopenharmony_ci#define PCH_RX_OK BIT(4) 628c2ecf20Sopenharmony_ci#define PCH_EPASSIV BIT(5) 638c2ecf20Sopenharmony_ci#define PCH_EWARN BIT(6) 648c2ecf20Sopenharmony_ci#define PCH_BUS_OFF BIT(7) 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci/* bit position of certain controller bits. */ 678c2ecf20Sopenharmony_ci#define PCH_BIT_BRP_SHIFT 0 688c2ecf20Sopenharmony_ci#define PCH_BIT_SJW_SHIFT 6 698c2ecf20Sopenharmony_ci#define PCH_BIT_TSEG1_SHIFT 8 708c2ecf20Sopenharmony_ci#define PCH_BIT_TSEG2_SHIFT 12 718c2ecf20Sopenharmony_ci#define PCH_BIT_BRPE_BRPE_SHIFT 6 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci#define PCH_MSK_BITT_BRP 0x3f 748c2ecf20Sopenharmony_ci#define PCH_MSK_BRPE_BRPE 0x3c0 758c2ecf20Sopenharmony_ci#define PCH_MSK_CTRL_IE_SIE_EIE 0x07 768c2ecf20Sopenharmony_ci#define PCH_COUNTER_LIMIT 10 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci#define PCH_CAN_CLK 50000000 /* 50MHz */ 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci/* 818c2ecf20Sopenharmony_ci * Define the number of message object. 828c2ecf20Sopenharmony_ci * PCH CAN communications are done via Message RAM. 838c2ecf20Sopenharmony_ci * The Message RAM consists of 32 message objects. 848c2ecf20Sopenharmony_ci */ 858c2ecf20Sopenharmony_ci#define PCH_RX_OBJ_NUM 26 868c2ecf20Sopenharmony_ci#define PCH_TX_OBJ_NUM 6 878c2ecf20Sopenharmony_ci#define PCH_RX_OBJ_START 1 888c2ecf20Sopenharmony_ci#define PCH_RX_OBJ_END PCH_RX_OBJ_NUM 898c2ecf20Sopenharmony_ci#define PCH_TX_OBJ_START (PCH_RX_OBJ_END + 1) 908c2ecf20Sopenharmony_ci#define PCH_TX_OBJ_END (PCH_RX_OBJ_NUM + PCH_TX_OBJ_NUM) 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci#define PCH_FIFO_THRESH 16 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci/* TxRqst2 show status of MsgObjNo.17~32 */ 958c2ecf20Sopenharmony_ci#define PCH_TREQ2_TX_MASK (((1 << PCH_TX_OBJ_NUM) - 1) <<\ 968c2ecf20Sopenharmony_ci (PCH_RX_OBJ_END - 16)) 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_cienum pch_ifreg { 998c2ecf20Sopenharmony_ci PCH_RX_IFREG, 1008c2ecf20Sopenharmony_ci PCH_TX_IFREG, 1018c2ecf20Sopenharmony_ci}; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cienum pch_can_err { 1048c2ecf20Sopenharmony_ci PCH_STUF_ERR = 1, 1058c2ecf20Sopenharmony_ci PCH_FORM_ERR, 1068c2ecf20Sopenharmony_ci PCH_ACK_ERR, 1078c2ecf20Sopenharmony_ci PCH_BIT1_ERR, 1088c2ecf20Sopenharmony_ci PCH_BIT0_ERR, 1098c2ecf20Sopenharmony_ci PCH_CRC_ERR, 1108c2ecf20Sopenharmony_ci PCH_LEC_ALL, 1118c2ecf20Sopenharmony_ci}; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_cienum pch_can_mode { 1148c2ecf20Sopenharmony_ci PCH_CAN_ENABLE, 1158c2ecf20Sopenharmony_ci PCH_CAN_DISABLE, 1168c2ecf20Sopenharmony_ci PCH_CAN_ALL, 1178c2ecf20Sopenharmony_ci PCH_CAN_NONE, 1188c2ecf20Sopenharmony_ci PCH_CAN_STOP, 1198c2ecf20Sopenharmony_ci PCH_CAN_RUN, 1208c2ecf20Sopenharmony_ci}; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_cistruct pch_can_if_regs { 1238c2ecf20Sopenharmony_ci u32 creq; 1248c2ecf20Sopenharmony_ci u32 cmask; 1258c2ecf20Sopenharmony_ci u32 mask1; 1268c2ecf20Sopenharmony_ci u32 mask2; 1278c2ecf20Sopenharmony_ci u32 id1; 1288c2ecf20Sopenharmony_ci u32 id2; 1298c2ecf20Sopenharmony_ci u32 mcont; 1308c2ecf20Sopenharmony_ci u32 data[4]; 1318c2ecf20Sopenharmony_ci u32 rsv[13]; 1328c2ecf20Sopenharmony_ci}; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cistruct pch_can_regs { 1358c2ecf20Sopenharmony_ci u32 cont; 1368c2ecf20Sopenharmony_ci u32 stat; 1378c2ecf20Sopenharmony_ci u32 errc; 1388c2ecf20Sopenharmony_ci u32 bitt; 1398c2ecf20Sopenharmony_ci u32 intr; 1408c2ecf20Sopenharmony_ci u32 opt; 1418c2ecf20Sopenharmony_ci u32 brpe; 1428c2ecf20Sopenharmony_ci u32 reserve; 1438c2ecf20Sopenharmony_ci struct pch_can_if_regs ifregs[2]; /* [0]=if1 [1]=if2 */ 1448c2ecf20Sopenharmony_ci u32 reserve1[8]; 1458c2ecf20Sopenharmony_ci u32 treq1; 1468c2ecf20Sopenharmony_ci u32 treq2; 1478c2ecf20Sopenharmony_ci u32 reserve2[6]; 1488c2ecf20Sopenharmony_ci u32 data1; 1498c2ecf20Sopenharmony_ci u32 data2; 1508c2ecf20Sopenharmony_ci u32 reserve3[6]; 1518c2ecf20Sopenharmony_ci u32 canipend1; 1528c2ecf20Sopenharmony_ci u32 canipend2; 1538c2ecf20Sopenharmony_ci u32 reserve4[6]; 1548c2ecf20Sopenharmony_ci u32 canmval1; 1558c2ecf20Sopenharmony_ci u32 canmval2; 1568c2ecf20Sopenharmony_ci u32 reserve5[37]; 1578c2ecf20Sopenharmony_ci u32 srst; 1588c2ecf20Sopenharmony_ci}; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_cistruct pch_can_priv { 1618c2ecf20Sopenharmony_ci struct can_priv can; 1628c2ecf20Sopenharmony_ci struct pci_dev *dev; 1638c2ecf20Sopenharmony_ci u32 tx_enable[PCH_TX_OBJ_END]; 1648c2ecf20Sopenharmony_ci u32 rx_enable[PCH_TX_OBJ_END]; 1658c2ecf20Sopenharmony_ci u32 rx_link[PCH_TX_OBJ_END]; 1668c2ecf20Sopenharmony_ci u32 int_enables; 1678c2ecf20Sopenharmony_ci struct net_device *ndev; 1688c2ecf20Sopenharmony_ci struct pch_can_regs __iomem *regs; 1698c2ecf20Sopenharmony_ci struct napi_struct napi; 1708c2ecf20Sopenharmony_ci int tx_obj; /* Point next Tx Obj index */ 1718c2ecf20Sopenharmony_ci int use_msi; 1728c2ecf20Sopenharmony_ci}; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_cistatic const struct can_bittiming_const pch_can_bittiming_const = { 1758c2ecf20Sopenharmony_ci .name = KBUILD_MODNAME, 1768c2ecf20Sopenharmony_ci .tseg1_min = 2, 1778c2ecf20Sopenharmony_ci .tseg1_max = 16, 1788c2ecf20Sopenharmony_ci .tseg2_min = 1, 1798c2ecf20Sopenharmony_ci .tseg2_max = 8, 1808c2ecf20Sopenharmony_ci .sjw_max = 4, 1818c2ecf20Sopenharmony_ci .brp_min = 1, 1828c2ecf20Sopenharmony_ci .brp_max = 1024, /* 6bit + extended 4bit */ 1838c2ecf20Sopenharmony_ci .brp_inc = 1, 1848c2ecf20Sopenharmony_ci}; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_cistatic const struct pci_device_id pch_pci_tbl[] = { 1878c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_INTEL, 0x8818, PCI_ANY_ID, PCI_ANY_ID,}, 1888c2ecf20Sopenharmony_ci {0,} 1898c2ecf20Sopenharmony_ci}; 1908c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, pch_pci_tbl); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_cistatic inline void pch_can_bit_set(void __iomem *addr, u32 mask) 1938c2ecf20Sopenharmony_ci{ 1948c2ecf20Sopenharmony_ci iowrite32(ioread32(addr) | mask, addr); 1958c2ecf20Sopenharmony_ci} 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_cistatic inline void pch_can_bit_clear(void __iomem *addr, u32 mask) 1988c2ecf20Sopenharmony_ci{ 1998c2ecf20Sopenharmony_ci iowrite32(ioread32(addr) & ~mask, addr); 2008c2ecf20Sopenharmony_ci} 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_cistatic void pch_can_set_run_mode(struct pch_can_priv *priv, 2038c2ecf20Sopenharmony_ci enum pch_can_mode mode) 2048c2ecf20Sopenharmony_ci{ 2058c2ecf20Sopenharmony_ci switch (mode) { 2068c2ecf20Sopenharmony_ci case PCH_CAN_RUN: 2078c2ecf20Sopenharmony_ci pch_can_bit_clear(&priv->regs->cont, PCH_CTRL_INIT); 2088c2ecf20Sopenharmony_ci break; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci case PCH_CAN_STOP: 2118c2ecf20Sopenharmony_ci pch_can_bit_set(&priv->regs->cont, PCH_CTRL_INIT); 2128c2ecf20Sopenharmony_ci break; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci default: 2158c2ecf20Sopenharmony_ci netdev_err(priv->ndev, "%s -> Invalid Mode.\n", __func__); 2168c2ecf20Sopenharmony_ci break; 2178c2ecf20Sopenharmony_ci } 2188c2ecf20Sopenharmony_ci} 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_cistatic void pch_can_set_optmode(struct pch_can_priv *priv) 2218c2ecf20Sopenharmony_ci{ 2228c2ecf20Sopenharmony_ci u32 reg_val = ioread32(&priv->regs->opt); 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) 2258c2ecf20Sopenharmony_ci reg_val |= PCH_OPT_SILENT; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) 2288c2ecf20Sopenharmony_ci reg_val |= PCH_OPT_LBACK; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci pch_can_bit_set(&priv->regs->cont, PCH_CTRL_OPT); 2318c2ecf20Sopenharmony_ci iowrite32(reg_val, &priv->regs->opt); 2328c2ecf20Sopenharmony_ci} 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_cistatic void pch_can_rw_msg_obj(void __iomem *creq_addr, u32 num) 2358c2ecf20Sopenharmony_ci{ 2368c2ecf20Sopenharmony_ci int counter = PCH_COUNTER_LIMIT; 2378c2ecf20Sopenharmony_ci u32 ifx_creq; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci iowrite32(num, creq_addr); 2408c2ecf20Sopenharmony_ci while (counter) { 2418c2ecf20Sopenharmony_ci ifx_creq = ioread32(creq_addr) & PCH_IF_CREQ_BUSY; 2428c2ecf20Sopenharmony_ci if (!ifx_creq) 2438c2ecf20Sopenharmony_ci break; 2448c2ecf20Sopenharmony_ci counter--; 2458c2ecf20Sopenharmony_ci udelay(1); 2468c2ecf20Sopenharmony_ci } 2478c2ecf20Sopenharmony_ci if (!counter) 2488c2ecf20Sopenharmony_ci pr_err("%s:IF1 BUSY Flag is set forever.\n", __func__); 2498c2ecf20Sopenharmony_ci} 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_cistatic void pch_can_set_int_enables(struct pch_can_priv *priv, 2528c2ecf20Sopenharmony_ci enum pch_can_mode interrupt_no) 2538c2ecf20Sopenharmony_ci{ 2548c2ecf20Sopenharmony_ci switch (interrupt_no) { 2558c2ecf20Sopenharmony_ci case PCH_CAN_DISABLE: 2568c2ecf20Sopenharmony_ci pch_can_bit_clear(&priv->regs->cont, PCH_CTRL_IE); 2578c2ecf20Sopenharmony_ci break; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci case PCH_CAN_ALL: 2608c2ecf20Sopenharmony_ci pch_can_bit_set(&priv->regs->cont, PCH_CTRL_IE_SIE_EIE); 2618c2ecf20Sopenharmony_ci break; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci case PCH_CAN_NONE: 2648c2ecf20Sopenharmony_ci pch_can_bit_clear(&priv->regs->cont, PCH_CTRL_IE_SIE_EIE); 2658c2ecf20Sopenharmony_ci break; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci default: 2688c2ecf20Sopenharmony_ci netdev_err(priv->ndev, "Invalid interrupt number.\n"); 2698c2ecf20Sopenharmony_ci break; 2708c2ecf20Sopenharmony_ci } 2718c2ecf20Sopenharmony_ci} 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_cistatic void pch_can_set_rxtx(struct pch_can_priv *priv, u32 buff_num, 2748c2ecf20Sopenharmony_ci int set, enum pch_ifreg dir) 2758c2ecf20Sopenharmony_ci{ 2768c2ecf20Sopenharmony_ci u32 ie; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci if (dir) 2798c2ecf20Sopenharmony_ci ie = PCH_IF_MCONT_TXIE; 2808c2ecf20Sopenharmony_ci else 2818c2ecf20Sopenharmony_ci ie = PCH_IF_MCONT_RXIE; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci /* Reading the Msg buffer from Message RAM to IF1/2 registers. */ 2848c2ecf20Sopenharmony_ci iowrite32(PCH_CMASK_RX_TX_GET, &priv->regs->ifregs[dir].cmask); 2858c2ecf20Sopenharmony_ci pch_can_rw_msg_obj(&priv->regs->ifregs[dir].creq, buff_num); 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci /* Setting the IF1/2MASK1 register to access MsgVal and RxIE bits */ 2888c2ecf20Sopenharmony_ci iowrite32(PCH_CMASK_RDWR | PCH_CMASK_ARB | PCH_CMASK_CTRL, 2898c2ecf20Sopenharmony_ci &priv->regs->ifregs[dir].cmask); 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci if (set) { 2928c2ecf20Sopenharmony_ci /* Setting the MsgVal and RxIE/TxIE bits */ 2938c2ecf20Sopenharmony_ci pch_can_bit_set(&priv->regs->ifregs[dir].mcont, ie); 2948c2ecf20Sopenharmony_ci pch_can_bit_set(&priv->regs->ifregs[dir].id2, PCH_ID_MSGVAL); 2958c2ecf20Sopenharmony_ci } else { 2968c2ecf20Sopenharmony_ci /* Clearing the MsgVal and RxIE/TxIE bits */ 2978c2ecf20Sopenharmony_ci pch_can_bit_clear(&priv->regs->ifregs[dir].mcont, ie); 2988c2ecf20Sopenharmony_ci pch_can_bit_clear(&priv->regs->ifregs[dir].id2, PCH_ID_MSGVAL); 2998c2ecf20Sopenharmony_ci } 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci pch_can_rw_msg_obj(&priv->regs->ifregs[dir].creq, buff_num); 3028c2ecf20Sopenharmony_ci} 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_cistatic void pch_can_set_rx_all(struct pch_can_priv *priv, int set) 3058c2ecf20Sopenharmony_ci{ 3068c2ecf20Sopenharmony_ci int i; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci /* Traversing to obtain the object configured as receivers. */ 3098c2ecf20Sopenharmony_ci for (i = PCH_RX_OBJ_START; i <= PCH_RX_OBJ_END; i++) 3108c2ecf20Sopenharmony_ci pch_can_set_rxtx(priv, i, set, PCH_RX_IFREG); 3118c2ecf20Sopenharmony_ci} 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_cistatic void pch_can_set_tx_all(struct pch_can_priv *priv, int set) 3148c2ecf20Sopenharmony_ci{ 3158c2ecf20Sopenharmony_ci int i; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci /* Traversing to obtain the object configured as transmit object. */ 3188c2ecf20Sopenharmony_ci for (i = PCH_TX_OBJ_START; i <= PCH_TX_OBJ_END; i++) 3198c2ecf20Sopenharmony_ci pch_can_set_rxtx(priv, i, set, PCH_TX_IFREG); 3208c2ecf20Sopenharmony_ci} 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_cistatic u32 pch_can_int_pending(struct pch_can_priv *priv) 3238c2ecf20Sopenharmony_ci{ 3248c2ecf20Sopenharmony_ci return ioread32(&priv->regs->intr) & 0xffff; 3258c2ecf20Sopenharmony_ci} 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_cistatic void pch_can_clear_if_buffers(struct pch_can_priv *priv) 3288c2ecf20Sopenharmony_ci{ 3298c2ecf20Sopenharmony_ci int i; /* Msg Obj ID (1~32) */ 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci for (i = PCH_RX_OBJ_START; i <= PCH_TX_OBJ_END; i++) { 3328c2ecf20Sopenharmony_ci iowrite32(PCH_CMASK_RX_TX_SET, &priv->regs->ifregs[0].cmask); 3338c2ecf20Sopenharmony_ci iowrite32(0xffff, &priv->regs->ifregs[0].mask1); 3348c2ecf20Sopenharmony_ci iowrite32(0xffff, &priv->regs->ifregs[0].mask2); 3358c2ecf20Sopenharmony_ci iowrite32(0x0, &priv->regs->ifregs[0].id1); 3368c2ecf20Sopenharmony_ci iowrite32(0x0, &priv->regs->ifregs[0].id2); 3378c2ecf20Sopenharmony_ci iowrite32(0x0, &priv->regs->ifregs[0].mcont); 3388c2ecf20Sopenharmony_ci iowrite32(0x0, &priv->regs->ifregs[0].data[0]); 3398c2ecf20Sopenharmony_ci iowrite32(0x0, &priv->regs->ifregs[0].data[1]); 3408c2ecf20Sopenharmony_ci iowrite32(0x0, &priv->regs->ifregs[0].data[2]); 3418c2ecf20Sopenharmony_ci iowrite32(0x0, &priv->regs->ifregs[0].data[3]); 3428c2ecf20Sopenharmony_ci iowrite32(PCH_CMASK_RDWR | PCH_CMASK_MASK | 3438c2ecf20Sopenharmony_ci PCH_CMASK_ARB | PCH_CMASK_CTRL, 3448c2ecf20Sopenharmony_ci &priv->regs->ifregs[0].cmask); 3458c2ecf20Sopenharmony_ci pch_can_rw_msg_obj(&priv->regs->ifregs[0].creq, i); 3468c2ecf20Sopenharmony_ci } 3478c2ecf20Sopenharmony_ci} 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_cistatic void pch_can_config_rx_tx_buffers(struct pch_can_priv *priv) 3508c2ecf20Sopenharmony_ci{ 3518c2ecf20Sopenharmony_ci int i; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci for (i = PCH_RX_OBJ_START; i <= PCH_RX_OBJ_END; i++) { 3548c2ecf20Sopenharmony_ci iowrite32(PCH_CMASK_RX_TX_GET, &priv->regs->ifregs[0].cmask); 3558c2ecf20Sopenharmony_ci pch_can_rw_msg_obj(&priv->regs->ifregs[0].creq, i); 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci iowrite32(0x0, &priv->regs->ifregs[0].id1); 3588c2ecf20Sopenharmony_ci iowrite32(0x0, &priv->regs->ifregs[0].id2); 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci pch_can_bit_set(&priv->regs->ifregs[0].mcont, 3618c2ecf20Sopenharmony_ci PCH_IF_MCONT_UMASK); 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci /* In case FIFO mode, Last EoB of Rx Obj must be 1 */ 3648c2ecf20Sopenharmony_ci if (i == PCH_RX_OBJ_END) 3658c2ecf20Sopenharmony_ci pch_can_bit_set(&priv->regs->ifregs[0].mcont, 3668c2ecf20Sopenharmony_ci PCH_IF_MCONT_EOB); 3678c2ecf20Sopenharmony_ci else 3688c2ecf20Sopenharmony_ci pch_can_bit_clear(&priv->regs->ifregs[0].mcont, 3698c2ecf20Sopenharmony_ci PCH_IF_MCONT_EOB); 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci iowrite32(0, &priv->regs->ifregs[0].mask1); 3728c2ecf20Sopenharmony_ci pch_can_bit_clear(&priv->regs->ifregs[0].mask2, 3738c2ecf20Sopenharmony_ci 0x1fff | PCH_MASK2_MDIR_MXTD); 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci /* Setting CMASK for writing */ 3768c2ecf20Sopenharmony_ci iowrite32(PCH_CMASK_RDWR | PCH_CMASK_MASK | PCH_CMASK_ARB | 3778c2ecf20Sopenharmony_ci PCH_CMASK_CTRL, &priv->regs->ifregs[0].cmask); 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci pch_can_rw_msg_obj(&priv->regs->ifregs[0].creq, i); 3808c2ecf20Sopenharmony_ci } 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci for (i = PCH_TX_OBJ_START; i <= PCH_TX_OBJ_END; i++) { 3838c2ecf20Sopenharmony_ci iowrite32(PCH_CMASK_RX_TX_GET, &priv->regs->ifregs[1].cmask); 3848c2ecf20Sopenharmony_ci pch_can_rw_msg_obj(&priv->regs->ifregs[1].creq, i); 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci /* Resetting DIR bit for reception */ 3878c2ecf20Sopenharmony_ci iowrite32(0x0, &priv->regs->ifregs[1].id1); 3888c2ecf20Sopenharmony_ci iowrite32(PCH_ID2_DIR, &priv->regs->ifregs[1].id2); 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci /* Setting EOB bit for transmitter */ 3918c2ecf20Sopenharmony_ci iowrite32(PCH_IF_MCONT_EOB | PCH_IF_MCONT_UMASK, 3928c2ecf20Sopenharmony_ci &priv->regs->ifregs[1].mcont); 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci iowrite32(0, &priv->regs->ifregs[1].mask1); 3958c2ecf20Sopenharmony_ci pch_can_bit_clear(&priv->regs->ifregs[1].mask2, 0x1fff); 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci /* Setting CMASK for writing */ 3988c2ecf20Sopenharmony_ci iowrite32(PCH_CMASK_RDWR | PCH_CMASK_MASK | PCH_CMASK_ARB | 3998c2ecf20Sopenharmony_ci PCH_CMASK_CTRL, &priv->regs->ifregs[1].cmask); 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci pch_can_rw_msg_obj(&priv->regs->ifregs[1].creq, i); 4028c2ecf20Sopenharmony_ci } 4038c2ecf20Sopenharmony_ci} 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_cistatic void pch_can_init(struct pch_can_priv *priv) 4068c2ecf20Sopenharmony_ci{ 4078c2ecf20Sopenharmony_ci /* Stopping the Can device. */ 4088c2ecf20Sopenharmony_ci pch_can_set_run_mode(priv, PCH_CAN_STOP); 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci /* Clearing all the message object buffers. */ 4118c2ecf20Sopenharmony_ci pch_can_clear_if_buffers(priv); 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci /* Configuring the respective message object as either rx/tx object. */ 4148c2ecf20Sopenharmony_ci pch_can_config_rx_tx_buffers(priv); 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci /* Enabling the interrupts. */ 4178c2ecf20Sopenharmony_ci pch_can_set_int_enables(priv, PCH_CAN_ALL); 4188c2ecf20Sopenharmony_ci} 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_cistatic void pch_can_release(struct pch_can_priv *priv) 4218c2ecf20Sopenharmony_ci{ 4228c2ecf20Sopenharmony_ci /* Stooping the CAN device. */ 4238c2ecf20Sopenharmony_ci pch_can_set_run_mode(priv, PCH_CAN_STOP); 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci /* Disabling the interrupts. */ 4268c2ecf20Sopenharmony_ci pch_can_set_int_enables(priv, PCH_CAN_NONE); 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci /* Disabling all the receive object. */ 4298c2ecf20Sopenharmony_ci pch_can_set_rx_all(priv, 0); 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci /* Disabling all the transmit object. */ 4328c2ecf20Sopenharmony_ci pch_can_set_tx_all(priv, 0); 4338c2ecf20Sopenharmony_ci} 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci/* This function clears interrupt(s) from the CAN device. */ 4368c2ecf20Sopenharmony_cistatic void pch_can_int_clr(struct pch_can_priv *priv, u32 mask) 4378c2ecf20Sopenharmony_ci{ 4388c2ecf20Sopenharmony_ci /* Clear interrupt for transmit object */ 4398c2ecf20Sopenharmony_ci if ((mask >= PCH_RX_OBJ_START) && (mask <= PCH_RX_OBJ_END)) { 4408c2ecf20Sopenharmony_ci /* Setting CMASK for clearing the reception interrupts. */ 4418c2ecf20Sopenharmony_ci iowrite32(PCH_CMASK_RDWR | PCH_CMASK_CTRL | PCH_CMASK_ARB, 4428c2ecf20Sopenharmony_ci &priv->regs->ifregs[0].cmask); 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci /* Clearing the Dir bit. */ 4458c2ecf20Sopenharmony_ci pch_can_bit_clear(&priv->regs->ifregs[0].id2, PCH_ID2_DIR); 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci /* Clearing NewDat & IntPnd */ 4488c2ecf20Sopenharmony_ci pch_can_bit_clear(&priv->regs->ifregs[0].mcont, 4498c2ecf20Sopenharmony_ci PCH_IF_MCONT_NEWDAT | PCH_IF_MCONT_INTPND); 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci pch_can_rw_msg_obj(&priv->regs->ifregs[0].creq, mask); 4528c2ecf20Sopenharmony_ci } else if ((mask >= PCH_TX_OBJ_START) && (mask <= PCH_TX_OBJ_END)) { 4538c2ecf20Sopenharmony_ci /* 4548c2ecf20Sopenharmony_ci * Setting CMASK for clearing interrupts for frame transmission. 4558c2ecf20Sopenharmony_ci */ 4568c2ecf20Sopenharmony_ci iowrite32(PCH_CMASK_RDWR | PCH_CMASK_CTRL | PCH_CMASK_ARB, 4578c2ecf20Sopenharmony_ci &priv->regs->ifregs[1].cmask); 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci /* Resetting the ID registers. */ 4608c2ecf20Sopenharmony_ci pch_can_bit_set(&priv->regs->ifregs[1].id2, 4618c2ecf20Sopenharmony_ci PCH_ID2_DIR | (0x7ff << 2)); 4628c2ecf20Sopenharmony_ci iowrite32(0x0, &priv->regs->ifregs[1].id1); 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci /* Clearing NewDat, TxRqst & IntPnd */ 4658c2ecf20Sopenharmony_ci pch_can_bit_clear(&priv->regs->ifregs[1].mcont, 4668c2ecf20Sopenharmony_ci PCH_IF_MCONT_NEWDAT | PCH_IF_MCONT_INTPND | 4678c2ecf20Sopenharmony_ci PCH_IF_MCONT_TXRQXT); 4688c2ecf20Sopenharmony_ci pch_can_rw_msg_obj(&priv->regs->ifregs[1].creq, mask); 4698c2ecf20Sopenharmony_ci } 4708c2ecf20Sopenharmony_ci} 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_cistatic void pch_can_reset(struct pch_can_priv *priv) 4738c2ecf20Sopenharmony_ci{ 4748c2ecf20Sopenharmony_ci /* write to sw reset register */ 4758c2ecf20Sopenharmony_ci iowrite32(1, &priv->regs->srst); 4768c2ecf20Sopenharmony_ci iowrite32(0, &priv->regs->srst); 4778c2ecf20Sopenharmony_ci} 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_cistatic void pch_can_error(struct net_device *ndev, u32 status) 4808c2ecf20Sopenharmony_ci{ 4818c2ecf20Sopenharmony_ci struct sk_buff *skb; 4828c2ecf20Sopenharmony_ci struct pch_can_priv *priv = netdev_priv(ndev); 4838c2ecf20Sopenharmony_ci struct can_frame *cf; 4848c2ecf20Sopenharmony_ci u32 errc, lec; 4858c2ecf20Sopenharmony_ci struct net_device_stats *stats = &(priv->ndev->stats); 4868c2ecf20Sopenharmony_ci enum can_state state = priv->can.state; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci skb = alloc_can_err_skb(ndev, &cf); 4898c2ecf20Sopenharmony_ci if (!skb) 4908c2ecf20Sopenharmony_ci return; 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci errc = ioread32(&priv->regs->errc); 4938c2ecf20Sopenharmony_ci if (status & PCH_BUS_OFF) { 4948c2ecf20Sopenharmony_ci pch_can_set_tx_all(priv, 0); 4958c2ecf20Sopenharmony_ci pch_can_set_rx_all(priv, 0); 4968c2ecf20Sopenharmony_ci state = CAN_STATE_BUS_OFF; 4978c2ecf20Sopenharmony_ci cf->can_id |= CAN_ERR_BUSOFF; 4988c2ecf20Sopenharmony_ci priv->can.can_stats.bus_off++; 4998c2ecf20Sopenharmony_ci can_bus_off(ndev); 5008c2ecf20Sopenharmony_ci } else { 5018c2ecf20Sopenharmony_ci cf->data[6] = errc & PCH_TEC; 5028c2ecf20Sopenharmony_ci cf->data[7] = (errc & PCH_REC) >> 8; 5038c2ecf20Sopenharmony_ci } 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci /* Warning interrupt. */ 5068c2ecf20Sopenharmony_ci if (status & PCH_EWARN) { 5078c2ecf20Sopenharmony_ci state = CAN_STATE_ERROR_WARNING; 5088c2ecf20Sopenharmony_ci priv->can.can_stats.error_warning++; 5098c2ecf20Sopenharmony_ci cf->can_id |= CAN_ERR_CRTL; 5108c2ecf20Sopenharmony_ci if (((errc & PCH_REC) >> 8) > 96) 5118c2ecf20Sopenharmony_ci cf->data[1] |= CAN_ERR_CRTL_RX_WARNING; 5128c2ecf20Sopenharmony_ci if ((errc & PCH_TEC) > 96) 5138c2ecf20Sopenharmony_ci cf->data[1] |= CAN_ERR_CRTL_TX_WARNING; 5148c2ecf20Sopenharmony_ci netdev_dbg(ndev, 5158c2ecf20Sopenharmony_ci "%s -> Error Counter is more than 96.\n", __func__); 5168c2ecf20Sopenharmony_ci } 5178c2ecf20Sopenharmony_ci /* Error passive interrupt. */ 5188c2ecf20Sopenharmony_ci if (status & PCH_EPASSIV) { 5198c2ecf20Sopenharmony_ci priv->can.can_stats.error_passive++; 5208c2ecf20Sopenharmony_ci state = CAN_STATE_ERROR_PASSIVE; 5218c2ecf20Sopenharmony_ci cf->can_id |= CAN_ERR_CRTL; 5228c2ecf20Sopenharmony_ci if (errc & PCH_RP) 5238c2ecf20Sopenharmony_ci cf->data[1] |= CAN_ERR_CRTL_RX_PASSIVE; 5248c2ecf20Sopenharmony_ci if ((errc & PCH_TEC) > 127) 5258c2ecf20Sopenharmony_ci cf->data[1] |= CAN_ERR_CRTL_TX_PASSIVE; 5268c2ecf20Sopenharmony_ci netdev_dbg(ndev, 5278c2ecf20Sopenharmony_ci "%s -> CAN controller is ERROR PASSIVE .\n", __func__); 5288c2ecf20Sopenharmony_ci } 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci lec = status & PCH_LEC_ALL; 5318c2ecf20Sopenharmony_ci switch (lec) { 5328c2ecf20Sopenharmony_ci case PCH_STUF_ERR: 5338c2ecf20Sopenharmony_ci cf->data[2] |= CAN_ERR_PROT_STUFF; 5348c2ecf20Sopenharmony_ci priv->can.can_stats.bus_error++; 5358c2ecf20Sopenharmony_ci stats->rx_errors++; 5368c2ecf20Sopenharmony_ci break; 5378c2ecf20Sopenharmony_ci case PCH_FORM_ERR: 5388c2ecf20Sopenharmony_ci cf->data[2] |= CAN_ERR_PROT_FORM; 5398c2ecf20Sopenharmony_ci priv->can.can_stats.bus_error++; 5408c2ecf20Sopenharmony_ci stats->rx_errors++; 5418c2ecf20Sopenharmony_ci break; 5428c2ecf20Sopenharmony_ci case PCH_ACK_ERR: 5438c2ecf20Sopenharmony_ci cf->can_id |= CAN_ERR_ACK; 5448c2ecf20Sopenharmony_ci priv->can.can_stats.bus_error++; 5458c2ecf20Sopenharmony_ci stats->rx_errors++; 5468c2ecf20Sopenharmony_ci break; 5478c2ecf20Sopenharmony_ci case PCH_BIT1_ERR: 5488c2ecf20Sopenharmony_ci case PCH_BIT0_ERR: 5498c2ecf20Sopenharmony_ci cf->data[2] |= CAN_ERR_PROT_BIT; 5508c2ecf20Sopenharmony_ci priv->can.can_stats.bus_error++; 5518c2ecf20Sopenharmony_ci stats->rx_errors++; 5528c2ecf20Sopenharmony_ci break; 5538c2ecf20Sopenharmony_ci case PCH_CRC_ERR: 5548c2ecf20Sopenharmony_ci cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ; 5558c2ecf20Sopenharmony_ci priv->can.can_stats.bus_error++; 5568c2ecf20Sopenharmony_ci stats->rx_errors++; 5578c2ecf20Sopenharmony_ci break; 5588c2ecf20Sopenharmony_ci case PCH_LEC_ALL: /* Written by CPU. No error status */ 5598c2ecf20Sopenharmony_ci break; 5608c2ecf20Sopenharmony_ci } 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci priv->can.state = state; 5638c2ecf20Sopenharmony_ci netif_receive_skb(skb); 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci stats->rx_packets++; 5668c2ecf20Sopenharmony_ci stats->rx_bytes += cf->can_dlc; 5678c2ecf20Sopenharmony_ci} 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_cistatic irqreturn_t pch_can_interrupt(int irq, void *dev_id) 5708c2ecf20Sopenharmony_ci{ 5718c2ecf20Sopenharmony_ci struct net_device *ndev = (struct net_device *)dev_id; 5728c2ecf20Sopenharmony_ci struct pch_can_priv *priv = netdev_priv(ndev); 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci if (!pch_can_int_pending(priv)) 5758c2ecf20Sopenharmony_ci return IRQ_NONE; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci pch_can_set_int_enables(priv, PCH_CAN_NONE); 5788c2ecf20Sopenharmony_ci napi_schedule(&priv->napi); 5798c2ecf20Sopenharmony_ci return IRQ_HANDLED; 5808c2ecf20Sopenharmony_ci} 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_cistatic void pch_fifo_thresh(struct pch_can_priv *priv, int obj_id) 5838c2ecf20Sopenharmony_ci{ 5848c2ecf20Sopenharmony_ci if (obj_id < PCH_FIFO_THRESH) { 5858c2ecf20Sopenharmony_ci iowrite32(PCH_CMASK_RDWR | PCH_CMASK_CTRL | 5868c2ecf20Sopenharmony_ci PCH_CMASK_ARB, &priv->regs->ifregs[0].cmask); 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci /* Clearing the Dir bit. */ 5898c2ecf20Sopenharmony_ci pch_can_bit_clear(&priv->regs->ifregs[0].id2, PCH_ID2_DIR); 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci /* Clearing NewDat & IntPnd */ 5928c2ecf20Sopenharmony_ci pch_can_bit_clear(&priv->regs->ifregs[0].mcont, 5938c2ecf20Sopenharmony_ci PCH_IF_MCONT_INTPND); 5948c2ecf20Sopenharmony_ci pch_can_rw_msg_obj(&priv->regs->ifregs[0].creq, obj_id); 5958c2ecf20Sopenharmony_ci } else if (obj_id > PCH_FIFO_THRESH) { 5968c2ecf20Sopenharmony_ci pch_can_int_clr(priv, obj_id); 5978c2ecf20Sopenharmony_ci } else if (obj_id == PCH_FIFO_THRESH) { 5988c2ecf20Sopenharmony_ci int cnt; 5998c2ecf20Sopenharmony_ci for (cnt = 0; cnt < PCH_FIFO_THRESH; cnt++) 6008c2ecf20Sopenharmony_ci pch_can_int_clr(priv, cnt + 1); 6018c2ecf20Sopenharmony_ci } 6028c2ecf20Sopenharmony_ci} 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_cistatic void pch_can_rx_msg_lost(struct net_device *ndev, int obj_id) 6058c2ecf20Sopenharmony_ci{ 6068c2ecf20Sopenharmony_ci struct pch_can_priv *priv = netdev_priv(ndev); 6078c2ecf20Sopenharmony_ci struct net_device_stats *stats = &(priv->ndev->stats); 6088c2ecf20Sopenharmony_ci struct sk_buff *skb; 6098c2ecf20Sopenharmony_ci struct can_frame *cf; 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci netdev_dbg(priv->ndev, "Msg Obj is overwritten.\n"); 6128c2ecf20Sopenharmony_ci pch_can_bit_clear(&priv->regs->ifregs[0].mcont, 6138c2ecf20Sopenharmony_ci PCH_IF_MCONT_MSGLOST); 6148c2ecf20Sopenharmony_ci iowrite32(PCH_CMASK_RDWR | PCH_CMASK_CTRL, 6158c2ecf20Sopenharmony_ci &priv->regs->ifregs[0].cmask); 6168c2ecf20Sopenharmony_ci pch_can_rw_msg_obj(&priv->regs->ifregs[0].creq, obj_id); 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci skb = alloc_can_err_skb(ndev, &cf); 6198c2ecf20Sopenharmony_ci if (!skb) 6208c2ecf20Sopenharmony_ci return; 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci cf->can_id |= CAN_ERR_CRTL; 6238c2ecf20Sopenharmony_ci cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; 6248c2ecf20Sopenharmony_ci stats->rx_over_errors++; 6258c2ecf20Sopenharmony_ci stats->rx_errors++; 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci netif_receive_skb(skb); 6288c2ecf20Sopenharmony_ci} 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_cistatic int pch_can_rx_normal(struct net_device *ndev, u32 obj_num, int quota) 6318c2ecf20Sopenharmony_ci{ 6328c2ecf20Sopenharmony_ci u32 reg; 6338c2ecf20Sopenharmony_ci canid_t id; 6348c2ecf20Sopenharmony_ci int rcv_pkts = 0; 6358c2ecf20Sopenharmony_ci struct sk_buff *skb; 6368c2ecf20Sopenharmony_ci struct can_frame *cf; 6378c2ecf20Sopenharmony_ci struct pch_can_priv *priv = netdev_priv(ndev); 6388c2ecf20Sopenharmony_ci struct net_device_stats *stats = &(priv->ndev->stats); 6398c2ecf20Sopenharmony_ci int i; 6408c2ecf20Sopenharmony_ci u32 id2; 6418c2ecf20Sopenharmony_ci u16 data_reg; 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci do { 6448c2ecf20Sopenharmony_ci /* Reading the message object from the Message RAM */ 6458c2ecf20Sopenharmony_ci iowrite32(PCH_CMASK_RX_TX_GET, &priv->regs->ifregs[0].cmask); 6468c2ecf20Sopenharmony_ci pch_can_rw_msg_obj(&priv->regs->ifregs[0].creq, obj_num); 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci /* Reading the MCONT register. */ 6498c2ecf20Sopenharmony_ci reg = ioread32(&priv->regs->ifregs[0].mcont); 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci if (reg & PCH_IF_MCONT_EOB) 6528c2ecf20Sopenharmony_ci break; 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci /* If MsgLost bit set. */ 6558c2ecf20Sopenharmony_ci if (reg & PCH_IF_MCONT_MSGLOST) { 6568c2ecf20Sopenharmony_ci pch_can_rx_msg_lost(ndev, obj_num); 6578c2ecf20Sopenharmony_ci rcv_pkts++; 6588c2ecf20Sopenharmony_ci quota--; 6598c2ecf20Sopenharmony_ci obj_num++; 6608c2ecf20Sopenharmony_ci continue; 6618c2ecf20Sopenharmony_ci } else if (!(reg & PCH_IF_MCONT_NEWDAT)) { 6628c2ecf20Sopenharmony_ci obj_num++; 6638c2ecf20Sopenharmony_ci continue; 6648c2ecf20Sopenharmony_ci } 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci skb = alloc_can_skb(priv->ndev, &cf); 6678c2ecf20Sopenharmony_ci if (!skb) { 6688c2ecf20Sopenharmony_ci netdev_err(ndev, "alloc_can_skb Failed\n"); 6698c2ecf20Sopenharmony_ci return rcv_pkts; 6708c2ecf20Sopenharmony_ci } 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci /* Get Received data */ 6738c2ecf20Sopenharmony_ci id2 = ioread32(&priv->regs->ifregs[0].id2); 6748c2ecf20Sopenharmony_ci if (id2 & PCH_ID2_XTD) { 6758c2ecf20Sopenharmony_ci id = (ioread32(&priv->regs->ifregs[0].id1) & 0xffff); 6768c2ecf20Sopenharmony_ci id |= (((id2) & 0x1fff) << 16); 6778c2ecf20Sopenharmony_ci cf->can_id = id | CAN_EFF_FLAG; 6788c2ecf20Sopenharmony_ci } else { 6798c2ecf20Sopenharmony_ci id = (id2 >> 2) & CAN_SFF_MASK; 6808c2ecf20Sopenharmony_ci cf->can_id = id; 6818c2ecf20Sopenharmony_ci } 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci if (id2 & PCH_ID2_DIR) 6848c2ecf20Sopenharmony_ci cf->can_id |= CAN_RTR_FLAG; 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci cf->can_dlc = get_can_dlc((ioread32(&priv->regs-> 6878c2ecf20Sopenharmony_ci ifregs[0].mcont)) & 0xF); 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci for (i = 0; i < cf->can_dlc; i += 2) { 6908c2ecf20Sopenharmony_ci data_reg = ioread16(&priv->regs->ifregs[0].data[i / 2]); 6918c2ecf20Sopenharmony_ci cf->data[i] = data_reg; 6928c2ecf20Sopenharmony_ci cf->data[i + 1] = data_reg >> 8; 6938c2ecf20Sopenharmony_ci } 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci rcv_pkts++; 6968c2ecf20Sopenharmony_ci stats->rx_packets++; 6978c2ecf20Sopenharmony_ci quota--; 6988c2ecf20Sopenharmony_ci stats->rx_bytes += cf->can_dlc; 6998c2ecf20Sopenharmony_ci netif_receive_skb(skb); 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci pch_fifo_thresh(priv, obj_num); 7028c2ecf20Sopenharmony_ci obj_num++; 7038c2ecf20Sopenharmony_ci } while (quota > 0); 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci return rcv_pkts; 7068c2ecf20Sopenharmony_ci} 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_cistatic void pch_can_tx_complete(struct net_device *ndev, u32 int_stat) 7098c2ecf20Sopenharmony_ci{ 7108c2ecf20Sopenharmony_ci struct pch_can_priv *priv = netdev_priv(ndev); 7118c2ecf20Sopenharmony_ci struct net_device_stats *stats = &(priv->ndev->stats); 7128c2ecf20Sopenharmony_ci u32 dlc; 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci can_get_echo_skb(ndev, int_stat - PCH_RX_OBJ_END - 1); 7158c2ecf20Sopenharmony_ci iowrite32(PCH_CMASK_RX_TX_GET | PCH_CMASK_CLRINTPND, 7168c2ecf20Sopenharmony_ci &priv->regs->ifregs[1].cmask); 7178c2ecf20Sopenharmony_ci pch_can_rw_msg_obj(&priv->regs->ifregs[1].creq, int_stat); 7188c2ecf20Sopenharmony_ci dlc = get_can_dlc(ioread32(&priv->regs->ifregs[1].mcont) & 7198c2ecf20Sopenharmony_ci PCH_IF_MCONT_DLC); 7208c2ecf20Sopenharmony_ci stats->tx_bytes += dlc; 7218c2ecf20Sopenharmony_ci stats->tx_packets++; 7228c2ecf20Sopenharmony_ci if (int_stat == PCH_TX_OBJ_END) 7238c2ecf20Sopenharmony_ci netif_wake_queue(ndev); 7248c2ecf20Sopenharmony_ci} 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_cistatic int pch_can_poll(struct napi_struct *napi, int quota) 7278c2ecf20Sopenharmony_ci{ 7288c2ecf20Sopenharmony_ci struct net_device *ndev = napi->dev; 7298c2ecf20Sopenharmony_ci struct pch_can_priv *priv = netdev_priv(ndev); 7308c2ecf20Sopenharmony_ci u32 int_stat; 7318c2ecf20Sopenharmony_ci u32 reg_stat; 7328c2ecf20Sopenharmony_ci int quota_save = quota; 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci int_stat = pch_can_int_pending(priv); 7358c2ecf20Sopenharmony_ci if (!int_stat) 7368c2ecf20Sopenharmony_ci goto end; 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci if (int_stat == PCH_STATUS_INT) { 7398c2ecf20Sopenharmony_ci reg_stat = ioread32(&priv->regs->stat); 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci if ((reg_stat & (PCH_BUS_OFF | PCH_LEC_ALL)) && 7428c2ecf20Sopenharmony_ci ((reg_stat & PCH_LEC_ALL) != PCH_LEC_ALL)) { 7438c2ecf20Sopenharmony_ci pch_can_error(ndev, reg_stat); 7448c2ecf20Sopenharmony_ci quota--; 7458c2ecf20Sopenharmony_ci } 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci if (reg_stat & (PCH_TX_OK | PCH_RX_OK)) 7488c2ecf20Sopenharmony_ci pch_can_bit_clear(&priv->regs->stat, 7498c2ecf20Sopenharmony_ci reg_stat & (PCH_TX_OK | PCH_RX_OK)); 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci int_stat = pch_can_int_pending(priv); 7528c2ecf20Sopenharmony_ci } 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci if (quota == 0) 7558c2ecf20Sopenharmony_ci goto end; 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci if ((int_stat >= PCH_RX_OBJ_START) && (int_stat <= PCH_RX_OBJ_END)) { 7588c2ecf20Sopenharmony_ci quota -= pch_can_rx_normal(ndev, int_stat, quota); 7598c2ecf20Sopenharmony_ci } else if ((int_stat >= PCH_TX_OBJ_START) && 7608c2ecf20Sopenharmony_ci (int_stat <= PCH_TX_OBJ_END)) { 7618c2ecf20Sopenharmony_ci /* Handle transmission interrupt */ 7628c2ecf20Sopenharmony_ci pch_can_tx_complete(ndev, int_stat); 7638c2ecf20Sopenharmony_ci } 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ciend: 7668c2ecf20Sopenharmony_ci napi_complete(napi); 7678c2ecf20Sopenharmony_ci pch_can_set_int_enables(priv, PCH_CAN_ALL); 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci return quota_save - quota; 7708c2ecf20Sopenharmony_ci} 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_cistatic int pch_set_bittiming(struct net_device *ndev) 7738c2ecf20Sopenharmony_ci{ 7748c2ecf20Sopenharmony_ci struct pch_can_priv *priv = netdev_priv(ndev); 7758c2ecf20Sopenharmony_ci const struct can_bittiming *bt = &priv->can.bittiming; 7768c2ecf20Sopenharmony_ci u32 canbit; 7778c2ecf20Sopenharmony_ci u32 bepe; 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci /* Setting the CCE bit for accessing the Can Timing register. */ 7808c2ecf20Sopenharmony_ci pch_can_bit_set(&priv->regs->cont, PCH_CTRL_CCE); 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci canbit = (bt->brp - 1) & PCH_MSK_BITT_BRP; 7838c2ecf20Sopenharmony_ci canbit |= (bt->sjw - 1) << PCH_BIT_SJW_SHIFT; 7848c2ecf20Sopenharmony_ci canbit |= (bt->phase_seg1 + bt->prop_seg - 1) << PCH_BIT_TSEG1_SHIFT; 7858c2ecf20Sopenharmony_ci canbit |= (bt->phase_seg2 - 1) << PCH_BIT_TSEG2_SHIFT; 7868c2ecf20Sopenharmony_ci bepe = ((bt->brp - 1) & PCH_MSK_BRPE_BRPE) >> PCH_BIT_BRPE_BRPE_SHIFT; 7878c2ecf20Sopenharmony_ci iowrite32(canbit, &priv->regs->bitt); 7888c2ecf20Sopenharmony_ci iowrite32(bepe, &priv->regs->brpe); 7898c2ecf20Sopenharmony_ci pch_can_bit_clear(&priv->regs->cont, PCH_CTRL_CCE); 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci return 0; 7928c2ecf20Sopenharmony_ci} 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_cistatic void pch_can_start(struct net_device *ndev) 7958c2ecf20Sopenharmony_ci{ 7968c2ecf20Sopenharmony_ci struct pch_can_priv *priv = netdev_priv(ndev); 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci if (priv->can.state != CAN_STATE_STOPPED) 7998c2ecf20Sopenharmony_ci pch_can_reset(priv); 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci pch_set_bittiming(ndev); 8028c2ecf20Sopenharmony_ci pch_can_set_optmode(priv); 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci pch_can_set_tx_all(priv, 1); 8058c2ecf20Sopenharmony_ci pch_can_set_rx_all(priv, 1); 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ci /* Setting the CAN to run mode. */ 8088c2ecf20Sopenharmony_ci pch_can_set_run_mode(priv, PCH_CAN_RUN); 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci priv->can.state = CAN_STATE_ERROR_ACTIVE; 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci return; 8138c2ecf20Sopenharmony_ci} 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_cistatic int pch_can_do_set_mode(struct net_device *ndev, enum can_mode mode) 8168c2ecf20Sopenharmony_ci{ 8178c2ecf20Sopenharmony_ci int ret = 0; 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci switch (mode) { 8208c2ecf20Sopenharmony_ci case CAN_MODE_START: 8218c2ecf20Sopenharmony_ci pch_can_start(ndev); 8228c2ecf20Sopenharmony_ci netif_wake_queue(ndev); 8238c2ecf20Sopenharmony_ci break; 8248c2ecf20Sopenharmony_ci default: 8258c2ecf20Sopenharmony_ci ret = -EOPNOTSUPP; 8268c2ecf20Sopenharmony_ci break; 8278c2ecf20Sopenharmony_ci } 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci return ret; 8308c2ecf20Sopenharmony_ci} 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_cistatic int pch_can_open(struct net_device *ndev) 8338c2ecf20Sopenharmony_ci{ 8348c2ecf20Sopenharmony_ci struct pch_can_priv *priv = netdev_priv(ndev); 8358c2ecf20Sopenharmony_ci int retval; 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci /* Registering the interrupt. */ 8388c2ecf20Sopenharmony_ci retval = request_irq(priv->dev->irq, pch_can_interrupt, IRQF_SHARED, 8398c2ecf20Sopenharmony_ci ndev->name, ndev); 8408c2ecf20Sopenharmony_ci if (retval) { 8418c2ecf20Sopenharmony_ci netdev_err(ndev, "request_irq failed.\n"); 8428c2ecf20Sopenharmony_ci goto req_irq_err; 8438c2ecf20Sopenharmony_ci } 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci /* Open common can device */ 8468c2ecf20Sopenharmony_ci retval = open_candev(ndev); 8478c2ecf20Sopenharmony_ci if (retval) { 8488c2ecf20Sopenharmony_ci netdev_err(ndev, "open_candev() failed %d\n", retval); 8498c2ecf20Sopenharmony_ci goto err_open_candev; 8508c2ecf20Sopenharmony_ci } 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci pch_can_init(priv); 8538c2ecf20Sopenharmony_ci pch_can_start(ndev); 8548c2ecf20Sopenharmony_ci napi_enable(&priv->napi); 8558c2ecf20Sopenharmony_ci netif_start_queue(ndev); 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci return 0; 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_cierr_open_candev: 8608c2ecf20Sopenharmony_ci free_irq(priv->dev->irq, ndev); 8618c2ecf20Sopenharmony_cireq_irq_err: 8628c2ecf20Sopenharmony_ci pch_can_release(priv); 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci return retval; 8658c2ecf20Sopenharmony_ci} 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_cistatic int pch_close(struct net_device *ndev) 8688c2ecf20Sopenharmony_ci{ 8698c2ecf20Sopenharmony_ci struct pch_can_priv *priv = netdev_priv(ndev); 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci netif_stop_queue(ndev); 8728c2ecf20Sopenharmony_ci napi_disable(&priv->napi); 8738c2ecf20Sopenharmony_ci pch_can_release(priv); 8748c2ecf20Sopenharmony_ci free_irq(priv->dev->irq, ndev); 8758c2ecf20Sopenharmony_ci close_candev(ndev); 8768c2ecf20Sopenharmony_ci priv->can.state = CAN_STATE_STOPPED; 8778c2ecf20Sopenharmony_ci return 0; 8788c2ecf20Sopenharmony_ci} 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_cistatic netdev_tx_t pch_xmit(struct sk_buff *skb, struct net_device *ndev) 8818c2ecf20Sopenharmony_ci{ 8828c2ecf20Sopenharmony_ci struct pch_can_priv *priv = netdev_priv(ndev); 8838c2ecf20Sopenharmony_ci struct can_frame *cf = (struct can_frame *)skb->data; 8848c2ecf20Sopenharmony_ci int tx_obj_no; 8858c2ecf20Sopenharmony_ci int i; 8868c2ecf20Sopenharmony_ci u32 id2; 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci if (can_dropped_invalid_skb(ndev, skb)) 8898c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci tx_obj_no = priv->tx_obj; 8928c2ecf20Sopenharmony_ci if (priv->tx_obj == PCH_TX_OBJ_END) { 8938c2ecf20Sopenharmony_ci if (ioread32(&priv->regs->treq2) & PCH_TREQ2_TX_MASK) 8948c2ecf20Sopenharmony_ci netif_stop_queue(ndev); 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci priv->tx_obj = PCH_TX_OBJ_START; 8978c2ecf20Sopenharmony_ci } else { 8988c2ecf20Sopenharmony_ci priv->tx_obj++; 8998c2ecf20Sopenharmony_ci } 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci /* Setting the CMASK register. */ 9028c2ecf20Sopenharmony_ci pch_can_bit_set(&priv->regs->ifregs[1].cmask, PCH_CMASK_ALL); 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci /* If ID extended is set. */ 9058c2ecf20Sopenharmony_ci if (cf->can_id & CAN_EFF_FLAG) { 9068c2ecf20Sopenharmony_ci iowrite32(cf->can_id & 0xffff, &priv->regs->ifregs[1].id1); 9078c2ecf20Sopenharmony_ci id2 = ((cf->can_id >> 16) & 0x1fff) | PCH_ID2_XTD; 9088c2ecf20Sopenharmony_ci } else { 9098c2ecf20Sopenharmony_ci iowrite32(0, &priv->regs->ifregs[1].id1); 9108c2ecf20Sopenharmony_ci id2 = (cf->can_id & CAN_SFF_MASK) << 2; 9118c2ecf20Sopenharmony_ci } 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci id2 |= PCH_ID_MSGVAL; 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci /* If remote frame has to be transmitted.. */ 9168c2ecf20Sopenharmony_ci if (!(cf->can_id & CAN_RTR_FLAG)) 9178c2ecf20Sopenharmony_ci id2 |= PCH_ID2_DIR; 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci iowrite32(id2, &priv->regs->ifregs[1].id2); 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci /* Copy data to register */ 9228c2ecf20Sopenharmony_ci for (i = 0; i < cf->can_dlc; i += 2) { 9238c2ecf20Sopenharmony_ci iowrite16(cf->data[i] | (cf->data[i + 1] << 8), 9248c2ecf20Sopenharmony_ci &priv->regs->ifregs[1].data[i / 2]); 9258c2ecf20Sopenharmony_ci } 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci can_put_echo_skb(skb, ndev, tx_obj_no - PCH_RX_OBJ_END - 1); 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_ci /* Set the size of the data. Update if2_mcont */ 9308c2ecf20Sopenharmony_ci iowrite32(cf->can_dlc | PCH_IF_MCONT_NEWDAT | PCH_IF_MCONT_TXRQXT | 9318c2ecf20Sopenharmony_ci PCH_IF_MCONT_TXIE, &priv->regs->ifregs[1].mcont); 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci pch_can_rw_msg_obj(&priv->regs->ifregs[1].creq, tx_obj_no); 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 9368c2ecf20Sopenharmony_ci} 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_cistatic const struct net_device_ops pch_can_netdev_ops = { 9398c2ecf20Sopenharmony_ci .ndo_open = pch_can_open, 9408c2ecf20Sopenharmony_ci .ndo_stop = pch_close, 9418c2ecf20Sopenharmony_ci .ndo_start_xmit = pch_xmit, 9428c2ecf20Sopenharmony_ci .ndo_change_mtu = can_change_mtu, 9438c2ecf20Sopenharmony_ci}; 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_cistatic void pch_can_remove(struct pci_dev *pdev) 9468c2ecf20Sopenharmony_ci{ 9478c2ecf20Sopenharmony_ci struct net_device *ndev = pci_get_drvdata(pdev); 9488c2ecf20Sopenharmony_ci struct pch_can_priv *priv = netdev_priv(ndev); 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci unregister_candev(priv->ndev); 9518c2ecf20Sopenharmony_ci if (priv->use_msi) 9528c2ecf20Sopenharmony_ci pci_disable_msi(priv->dev); 9538c2ecf20Sopenharmony_ci pci_release_regions(pdev); 9548c2ecf20Sopenharmony_ci pci_disable_device(pdev); 9558c2ecf20Sopenharmony_ci pch_can_reset(priv); 9568c2ecf20Sopenharmony_ci pci_iounmap(pdev, priv->regs); 9578c2ecf20Sopenharmony_ci free_candev(priv->ndev); 9588c2ecf20Sopenharmony_ci} 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_cistatic void __maybe_unused pch_can_set_int_custom(struct pch_can_priv *priv) 9618c2ecf20Sopenharmony_ci{ 9628c2ecf20Sopenharmony_ci /* Clearing the IE, SIE and EIE bits of Can control register. */ 9638c2ecf20Sopenharmony_ci pch_can_bit_clear(&priv->regs->cont, PCH_CTRL_IE_SIE_EIE); 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci /* Appropriately setting them. */ 9668c2ecf20Sopenharmony_ci pch_can_bit_set(&priv->regs->cont, 9678c2ecf20Sopenharmony_ci ((priv->int_enables & PCH_MSK_CTRL_IE_SIE_EIE) << 1)); 9688c2ecf20Sopenharmony_ci} 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ci/* This function retrieves interrupt enabled for the CAN device. */ 9718c2ecf20Sopenharmony_cistatic u32 __maybe_unused pch_can_get_int_enables(struct pch_can_priv *priv) 9728c2ecf20Sopenharmony_ci{ 9738c2ecf20Sopenharmony_ci /* Obtaining the status of IE, SIE and EIE interrupt bits. */ 9748c2ecf20Sopenharmony_ci return (ioread32(&priv->regs->cont) & PCH_CTRL_IE_SIE_EIE) >> 1; 9758c2ecf20Sopenharmony_ci} 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_cistatic u32 __maybe_unused pch_can_get_rxtx_ir(struct pch_can_priv *priv, 9788c2ecf20Sopenharmony_ci u32 buff_num, enum pch_ifreg dir) 9798c2ecf20Sopenharmony_ci{ 9808c2ecf20Sopenharmony_ci u32 ie, enable; 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci if (dir) 9838c2ecf20Sopenharmony_ci ie = PCH_IF_MCONT_RXIE; 9848c2ecf20Sopenharmony_ci else 9858c2ecf20Sopenharmony_ci ie = PCH_IF_MCONT_TXIE; 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_ci iowrite32(PCH_CMASK_RX_TX_GET, &priv->regs->ifregs[dir].cmask); 9888c2ecf20Sopenharmony_ci pch_can_rw_msg_obj(&priv->regs->ifregs[dir].creq, buff_num); 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci if (((ioread32(&priv->regs->ifregs[dir].id2)) & PCH_ID_MSGVAL) && 9918c2ecf20Sopenharmony_ci ((ioread32(&priv->regs->ifregs[dir].mcont)) & ie)) 9928c2ecf20Sopenharmony_ci enable = 1; 9938c2ecf20Sopenharmony_ci else 9948c2ecf20Sopenharmony_ci enable = 0; 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci return enable; 9978c2ecf20Sopenharmony_ci} 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_cistatic void __maybe_unused pch_can_set_rx_buffer_link(struct pch_can_priv *priv, 10008c2ecf20Sopenharmony_ci u32 buffer_num, int set) 10018c2ecf20Sopenharmony_ci{ 10028c2ecf20Sopenharmony_ci iowrite32(PCH_CMASK_RX_TX_GET, &priv->regs->ifregs[0].cmask); 10038c2ecf20Sopenharmony_ci pch_can_rw_msg_obj(&priv->regs->ifregs[0].creq, buffer_num); 10048c2ecf20Sopenharmony_ci iowrite32(PCH_CMASK_RDWR | PCH_CMASK_CTRL, 10058c2ecf20Sopenharmony_ci &priv->regs->ifregs[0].cmask); 10068c2ecf20Sopenharmony_ci if (set) 10078c2ecf20Sopenharmony_ci pch_can_bit_clear(&priv->regs->ifregs[0].mcont, 10088c2ecf20Sopenharmony_ci PCH_IF_MCONT_EOB); 10098c2ecf20Sopenharmony_ci else 10108c2ecf20Sopenharmony_ci pch_can_bit_set(&priv->regs->ifregs[0].mcont, PCH_IF_MCONT_EOB); 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci pch_can_rw_msg_obj(&priv->regs->ifregs[0].creq, buffer_num); 10138c2ecf20Sopenharmony_ci} 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_cistatic u32 __maybe_unused pch_can_get_rx_buffer_link(struct pch_can_priv *priv, 10168c2ecf20Sopenharmony_ci u32 buffer_num) 10178c2ecf20Sopenharmony_ci{ 10188c2ecf20Sopenharmony_ci u32 link; 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci iowrite32(PCH_CMASK_RX_TX_GET, &priv->regs->ifregs[0].cmask); 10218c2ecf20Sopenharmony_ci pch_can_rw_msg_obj(&priv->regs->ifregs[0].creq, buffer_num); 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_ci if (ioread32(&priv->regs->ifregs[0].mcont) & PCH_IF_MCONT_EOB) 10248c2ecf20Sopenharmony_ci link = 0; 10258c2ecf20Sopenharmony_ci else 10268c2ecf20Sopenharmony_ci link = 1; 10278c2ecf20Sopenharmony_ci return link; 10288c2ecf20Sopenharmony_ci} 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_cistatic int __maybe_unused pch_can_get_buffer_status(struct pch_can_priv *priv) 10318c2ecf20Sopenharmony_ci{ 10328c2ecf20Sopenharmony_ci return (ioread32(&priv->regs->treq1) & 0xffff) | 10338c2ecf20Sopenharmony_ci (ioread32(&priv->regs->treq2) << 16); 10348c2ecf20Sopenharmony_ci} 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_cistatic int __maybe_unused pch_can_suspend(struct device *dev_d) 10378c2ecf20Sopenharmony_ci{ 10388c2ecf20Sopenharmony_ci int i; 10398c2ecf20Sopenharmony_ci u32 buf_stat; /* Variable for reading the transmit buffer status. */ 10408c2ecf20Sopenharmony_ci int counter = PCH_COUNTER_LIMIT; 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci struct net_device *dev = dev_get_drvdata(dev_d); 10438c2ecf20Sopenharmony_ci struct pch_can_priv *priv = netdev_priv(dev); 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci /* Stop the CAN controller */ 10468c2ecf20Sopenharmony_ci pch_can_set_run_mode(priv, PCH_CAN_STOP); 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_ci /* Indicate that we are aboutto/in suspend */ 10498c2ecf20Sopenharmony_ci priv->can.state = CAN_STATE_STOPPED; 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci /* Waiting for all transmission to complete. */ 10528c2ecf20Sopenharmony_ci while (counter) { 10538c2ecf20Sopenharmony_ci buf_stat = pch_can_get_buffer_status(priv); 10548c2ecf20Sopenharmony_ci if (!buf_stat) 10558c2ecf20Sopenharmony_ci break; 10568c2ecf20Sopenharmony_ci counter--; 10578c2ecf20Sopenharmony_ci udelay(1); 10588c2ecf20Sopenharmony_ci } 10598c2ecf20Sopenharmony_ci if (!counter) 10608c2ecf20Sopenharmony_ci dev_err(dev_d, "%s -> Transmission time out.\n", __func__); 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci /* Save interrupt configuration and then disable them */ 10638c2ecf20Sopenharmony_ci priv->int_enables = pch_can_get_int_enables(priv); 10648c2ecf20Sopenharmony_ci pch_can_set_int_enables(priv, PCH_CAN_DISABLE); 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci /* Save Tx buffer enable state */ 10678c2ecf20Sopenharmony_ci for (i = PCH_TX_OBJ_START; i <= PCH_TX_OBJ_END; i++) 10688c2ecf20Sopenharmony_ci priv->tx_enable[i - 1] = pch_can_get_rxtx_ir(priv, i, 10698c2ecf20Sopenharmony_ci PCH_TX_IFREG); 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci /* Disable all Transmit buffers */ 10728c2ecf20Sopenharmony_ci pch_can_set_tx_all(priv, 0); 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci /* Save Rx buffer enable state */ 10758c2ecf20Sopenharmony_ci for (i = PCH_RX_OBJ_START; i <= PCH_RX_OBJ_END; i++) { 10768c2ecf20Sopenharmony_ci priv->rx_enable[i - 1] = pch_can_get_rxtx_ir(priv, i, 10778c2ecf20Sopenharmony_ci PCH_RX_IFREG); 10788c2ecf20Sopenharmony_ci priv->rx_link[i - 1] = pch_can_get_rx_buffer_link(priv, i); 10798c2ecf20Sopenharmony_ci } 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci /* Disable all Receive buffers */ 10828c2ecf20Sopenharmony_ci pch_can_set_rx_all(priv, 0); 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_ci return 0; 10858c2ecf20Sopenharmony_ci} 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_cistatic int __maybe_unused pch_can_resume(struct device *dev_d) 10888c2ecf20Sopenharmony_ci{ 10898c2ecf20Sopenharmony_ci int i; 10908c2ecf20Sopenharmony_ci struct net_device *dev = dev_get_drvdata(dev_d); 10918c2ecf20Sopenharmony_ci struct pch_can_priv *priv = netdev_priv(dev); 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_ci priv->can.state = CAN_STATE_ERROR_ACTIVE; 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ci /* Disabling all interrupts. */ 10968c2ecf20Sopenharmony_ci pch_can_set_int_enables(priv, PCH_CAN_DISABLE); 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci /* Setting the CAN device in Stop Mode. */ 10998c2ecf20Sopenharmony_ci pch_can_set_run_mode(priv, PCH_CAN_STOP); 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci /* Configuring the transmit and receive buffers. */ 11028c2ecf20Sopenharmony_ci pch_can_config_rx_tx_buffers(priv); 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci /* Restore the CAN state */ 11058c2ecf20Sopenharmony_ci pch_set_bittiming(dev); 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci /* Listen/Active */ 11088c2ecf20Sopenharmony_ci pch_can_set_optmode(priv); 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci /* Enabling the transmit buffer. */ 11118c2ecf20Sopenharmony_ci for (i = PCH_TX_OBJ_START; i <= PCH_TX_OBJ_END; i++) 11128c2ecf20Sopenharmony_ci pch_can_set_rxtx(priv, i, priv->tx_enable[i - 1], PCH_TX_IFREG); 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_ci /* Configuring the receive buffer and enabling them. */ 11158c2ecf20Sopenharmony_ci for (i = PCH_RX_OBJ_START; i <= PCH_RX_OBJ_END; i++) { 11168c2ecf20Sopenharmony_ci /* Restore buffer link */ 11178c2ecf20Sopenharmony_ci pch_can_set_rx_buffer_link(priv, i, priv->rx_link[i - 1]); 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci /* Restore buffer enables */ 11208c2ecf20Sopenharmony_ci pch_can_set_rxtx(priv, i, priv->rx_enable[i - 1], PCH_RX_IFREG); 11218c2ecf20Sopenharmony_ci } 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci /* Enable CAN Interrupts */ 11248c2ecf20Sopenharmony_ci pch_can_set_int_custom(priv); 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ci /* Restore Run Mode */ 11278c2ecf20Sopenharmony_ci pch_can_set_run_mode(priv, PCH_CAN_RUN); 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci return 0; 11308c2ecf20Sopenharmony_ci} 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_cistatic int pch_can_get_berr_counter(const struct net_device *dev, 11338c2ecf20Sopenharmony_ci struct can_berr_counter *bec) 11348c2ecf20Sopenharmony_ci{ 11358c2ecf20Sopenharmony_ci struct pch_can_priv *priv = netdev_priv(dev); 11368c2ecf20Sopenharmony_ci u32 errc = ioread32(&priv->regs->errc); 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci bec->txerr = errc & PCH_TEC; 11398c2ecf20Sopenharmony_ci bec->rxerr = (errc & PCH_REC) >> 8; 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_ci return 0; 11428c2ecf20Sopenharmony_ci} 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_cistatic int pch_can_probe(struct pci_dev *pdev, 11458c2ecf20Sopenharmony_ci const struct pci_device_id *id) 11468c2ecf20Sopenharmony_ci{ 11478c2ecf20Sopenharmony_ci struct net_device *ndev; 11488c2ecf20Sopenharmony_ci struct pch_can_priv *priv; 11498c2ecf20Sopenharmony_ci int rc; 11508c2ecf20Sopenharmony_ci void __iomem *addr; 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_ci rc = pci_enable_device(pdev); 11538c2ecf20Sopenharmony_ci if (rc) { 11548c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed pci_enable_device %d\n", rc); 11558c2ecf20Sopenharmony_ci goto probe_exit_endev; 11568c2ecf20Sopenharmony_ci } 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_ci rc = pci_request_regions(pdev, KBUILD_MODNAME); 11598c2ecf20Sopenharmony_ci if (rc) { 11608c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed pci_request_regions %d\n", rc); 11618c2ecf20Sopenharmony_ci goto probe_exit_pcireq; 11628c2ecf20Sopenharmony_ci } 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ci addr = pci_iomap(pdev, 1, 0); 11658c2ecf20Sopenharmony_ci if (!addr) { 11668c2ecf20Sopenharmony_ci rc = -EIO; 11678c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed pci_iomap\n"); 11688c2ecf20Sopenharmony_ci goto probe_exit_ipmap; 11698c2ecf20Sopenharmony_ci } 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci ndev = alloc_candev(sizeof(struct pch_can_priv), PCH_TX_OBJ_END); 11728c2ecf20Sopenharmony_ci if (!ndev) { 11738c2ecf20Sopenharmony_ci rc = -ENOMEM; 11748c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed alloc_candev\n"); 11758c2ecf20Sopenharmony_ci goto probe_exit_alloc_candev; 11768c2ecf20Sopenharmony_ci } 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci priv = netdev_priv(ndev); 11798c2ecf20Sopenharmony_ci priv->ndev = ndev; 11808c2ecf20Sopenharmony_ci priv->regs = addr; 11818c2ecf20Sopenharmony_ci priv->dev = pdev; 11828c2ecf20Sopenharmony_ci priv->can.bittiming_const = &pch_can_bittiming_const; 11838c2ecf20Sopenharmony_ci priv->can.do_set_mode = pch_can_do_set_mode; 11848c2ecf20Sopenharmony_ci priv->can.do_get_berr_counter = pch_can_get_berr_counter; 11858c2ecf20Sopenharmony_ci priv->can.ctrlmode_supported = CAN_CTRLMODE_LISTENONLY | 11868c2ecf20Sopenharmony_ci CAN_CTRLMODE_LOOPBACK; 11878c2ecf20Sopenharmony_ci priv->tx_obj = PCH_TX_OBJ_START; /* Point head of Tx Obj */ 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_ci ndev->irq = pdev->irq; 11908c2ecf20Sopenharmony_ci ndev->flags |= IFF_ECHO; 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, ndev); 11938c2ecf20Sopenharmony_ci SET_NETDEV_DEV(ndev, &pdev->dev); 11948c2ecf20Sopenharmony_ci ndev->netdev_ops = &pch_can_netdev_ops; 11958c2ecf20Sopenharmony_ci priv->can.clock.freq = PCH_CAN_CLK; /* Hz */ 11968c2ecf20Sopenharmony_ci 11978c2ecf20Sopenharmony_ci netif_napi_add(ndev, &priv->napi, pch_can_poll, PCH_RX_OBJ_END); 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_ci rc = pci_enable_msi(priv->dev); 12008c2ecf20Sopenharmony_ci if (rc) { 12018c2ecf20Sopenharmony_ci netdev_err(ndev, "PCH CAN opened without MSI\n"); 12028c2ecf20Sopenharmony_ci priv->use_msi = 0; 12038c2ecf20Sopenharmony_ci } else { 12048c2ecf20Sopenharmony_ci netdev_err(ndev, "PCH CAN opened with MSI\n"); 12058c2ecf20Sopenharmony_ci pci_set_master(pdev); 12068c2ecf20Sopenharmony_ci priv->use_msi = 1; 12078c2ecf20Sopenharmony_ci } 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_ci rc = register_candev(ndev); 12108c2ecf20Sopenharmony_ci if (rc) { 12118c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed register_candev %d\n", rc); 12128c2ecf20Sopenharmony_ci goto probe_exit_reg_candev; 12138c2ecf20Sopenharmony_ci } 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_ci return 0; 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_ciprobe_exit_reg_candev: 12188c2ecf20Sopenharmony_ci if (priv->use_msi) 12198c2ecf20Sopenharmony_ci pci_disable_msi(priv->dev); 12208c2ecf20Sopenharmony_ci free_candev(ndev); 12218c2ecf20Sopenharmony_ciprobe_exit_alloc_candev: 12228c2ecf20Sopenharmony_ci pci_iounmap(pdev, addr); 12238c2ecf20Sopenharmony_ciprobe_exit_ipmap: 12248c2ecf20Sopenharmony_ci pci_release_regions(pdev); 12258c2ecf20Sopenharmony_ciprobe_exit_pcireq: 12268c2ecf20Sopenharmony_ci pci_disable_device(pdev); 12278c2ecf20Sopenharmony_ciprobe_exit_endev: 12288c2ecf20Sopenharmony_ci return rc; 12298c2ecf20Sopenharmony_ci} 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(pch_can_pm_ops, 12328c2ecf20Sopenharmony_ci pch_can_suspend, 12338c2ecf20Sopenharmony_ci pch_can_resume); 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_cistatic struct pci_driver pch_can_pci_driver = { 12368c2ecf20Sopenharmony_ci .name = "pch_can", 12378c2ecf20Sopenharmony_ci .id_table = pch_pci_tbl, 12388c2ecf20Sopenharmony_ci .probe = pch_can_probe, 12398c2ecf20Sopenharmony_ci .remove = pch_can_remove, 12408c2ecf20Sopenharmony_ci .driver.pm = &pch_can_pm_ops, 12418c2ecf20Sopenharmony_ci}; 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_cimodule_pci_driver(pch_can_pci_driver); 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Intel EG20T PCH CAN(Controller Area Network) Driver"); 12468c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 12478c2ecf20Sopenharmony_ciMODULE_VERSION("0.94"); 1248