12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310 |
- // SPDX-License-Identifier: GPL-2.0-or-later
- /* Freescale QUICC Engine HDLC Device Driver
- *
- * Copyright 2016 Freescale Semiconductor Inc.
- */
- #include <linux/delay.h>
- #include <linux/dma-mapping.h>
- #include <linux/hdlc.h>
- #include <linux/init.h>
- #include <linux/interrupt.h>
- #include <linux/io.h>
- #include <linux/irq.h>
- #include <linux/kernel.h>
- #include <linux/module.h>
- #include <linux/netdevice.h>
- #include <linux/of_address.h>
- #include <linux/of_irq.h>
- #include <linux/of_platform.h>
- #include <linux/platform_device.h>
- #include <linux/sched.h>
- #include <linux/skbuff.h>
- #include <linux/slab.h>
- #include <linux/spinlock.h>
- #include <linux/stddef.h>
- #include <soc/fsl/qe/qe_tdm.h>
- #include <uapi/linux/if_arp.h>
- #include "fsl_ucc_hdlc.h"
- #define DRV_DESC "Freescale QE UCC HDLC Driver"
- #define DRV_NAME "ucc_hdlc"
- #define TDM_PPPOHT_SLIC_MAXIN
- #define RX_BD_ERRORS (R_CD_S | R_OV_S | R_CR_S | R_AB_S | R_NO_S | R_LG_S)
- static int uhdlc_close(struct net_device *dev);
- static struct ucc_tdm_info utdm_primary_info = {
- .uf_info = {
- .tsa = 0,
- .cdp = 0,
- .cds = 1,
- .ctsp = 1,
- .ctss = 1,
- .revd = 0,
- .urfs = 256,
- .utfs = 256,
- .urfet = 128,
- .urfset = 192,
- .utfet = 128,
- .utftt = 0x40,
- .ufpt = 256,
- .mode = UCC_FAST_PROTOCOL_MODE_HDLC,
- .ttx_trx = UCC_FAST_GUMR_TRANSPARENT_TTX_TRX_NORMAL,
- .tenc = UCC_FAST_TX_ENCODING_NRZ,
- .renc = UCC_FAST_RX_ENCODING_NRZ,
- .tcrc = UCC_FAST_16_BIT_CRC,
- .synl = UCC_FAST_SYNC_LEN_NOT_USED,
- },
- .si_info = {
- #ifdef TDM_PPPOHT_SLIC_MAXIN
- .simr_rfsd = 1,
- .simr_tfsd = 2,
- #else
- .simr_rfsd = 0,
- .simr_tfsd = 0,
- #endif
- .simr_crt = 0,
- .simr_sl = 0,
- .simr_ce = 1,
- .simr_fe = 1,
- .simr_gm = 0,
- },
- };
- static struct ucc_tdm_info utdm_info[UCC_MAX_NUM];
- static int uhdlc_init(struct ucc_hdlc_private *priv)
- {
- struct ucc_tdm_info *ut_info;
- struct ucc_fast_info *uf_info;
- u32 cecr_subblock;
- u16 bd_status;
- int ret, i;
- void *bd_buffer;
- dma_addr_t bd_dma_addr;
- s32 riptr;
- s32 tiptr;
- u32 gumr;
- ut_info = priv->ut_info;
- uf_info = &ut_info->uf_info;
- if (priv->tsa) {
- uf_info->tsa = 1;
- uf_info->ctsp = 1;
- uf_info->cds = 1;
- uf_info->ctss = 1;
- } else {
- uf_info->cds = 0;
- uf_info->ctsp = 0;
- uf_info->ctss = 0;
- }
- /* This sets HPM register in CMXUCR register which configures a
- * open drain connected HDLC bus
- */
- if (priv->hdlc_bus)
- uf_info->brkpt_support = 1;
- uf_info->uccm_mask = ((UCC_HDLC_UCCE_RXB | UCC_HDLC_UCCE_RXF |
- UCC_HDLC_UCCE_TXB) << 16);
- ret = ucc_fast_init(uf_info, &priv->uccf);
- if (ret) {
- dev_err(priv->dev, "Failed to init uccf.");
- return ret;
- }
- priv->uf_regs = priv->uccf->uf_regs;
- ucc_fast_disable(priv->uccf, COMM_DIR_RX | COMM_DIR_TX);
- /* Loopback mode */
- if (priv->loopback) {
- dev_info(priv->dev, "Loopback Mode\n");
- /* use the same clock when work in loopback */
- qe_setbrg(ut_info->uf_info.rx_clock, 20000000, 1);
- gumr = ioread32be(&priv->uf_regs->gumr);
- gumr |= (UCC_FAST_GUMR_LOOPBACK | UCC_FAST_GUMR_CDS |
- UCC_FAST_GUMR_TCI);
- gumr &= ~(UCC_FAST_GUMR_CTSP | UCC_FAST_GUMR_RSYN);
- iowrite32be(gumr, &priv->uf_regs->gumr);
- }
- /* Initialize SI */
- if (priv->tsa)
- ucc_tdm_init(priv->utdm, priv->ut_info);
- /* Write to QE CECR, UCCx channel to Stop Transmission */
- cecr_subblock = ucc_fast_get_qe_cr_subblock(uf_info->ucc_num);
- ret = qe_issue_cmd(QE_STOP_TX, cecr_subblock,
- QE_CR_PROTOCOL_UNSPECIFIED, 0);
- /* Set UPSMR normal mode (need fixed)*/
- iowrite32be(0, &priv->uf_regs->upsmr);
- /* hdlc_bus mode */
- if (priv->hdlc_bus) {
- u32 upsmr;
- dev_info(priv->dev, "HDLC bus Mode\n");
- upsmr = ioread32be(&priv->uf_regs->upsmr);
- /* bus mode and retransmit enable, with collision window
- * set to 8 bytes
- */
- upsmr |= UCC_HDLC_UPSMR_RTE | UCC_HDLC_UPSMR_BUS |
- UCC_HDLC_UPSMR_CW8;
- iowrite32be(upsmr, &priv->uf_regs->upsmr);
- /* explicitly disable CDS & CTSP */
- gumr = ioread32be(&priv->uf_regs->gumr);
- gumr &= ~(UCC_FAST_GUMR_CDS | UCC_FAST_GUMR_CTSP);
- /* set automatic sync to explicitly ignore CD signal */
- gumr |= UCC_FAST_GUMR_SYNL_AUTO;
- iowrite32be(gumr, &priv->uf_regs->gumr);
- }
- priv->rx_ring_size = RX_BD_RING_LEN;
- priv->tx_ring_size = TX_BD_RING_LEN;
- /* Alloc Rx BD */
- priv->rx_bd_base = dma_alloc_coherent(priv->dev,
- RX_BD_RING_LEN * sizeof(struct qe_bd),
- &priv->dma_rx_bd, GFP_KERNEL);
- if (!priv->rx_bd_base) {
- dev_err(priv->dev, "Cannot allocate MURAM memory for RxBDs\n");
- ret = -ENOMEM;
- goto free_uccf;
- }
- /* Alloc Tx BD */
- priv->tx_bd_base = dma_alloc_coherent(priv->dev,
- TX_BD_RING_LEN * sizeof(struct qe_bd),
- &priv->dma_tx_bd, GFP_KERNEL);
- if (!priv->tx_bd_base) {
- dev_err(priv->dev, "Cannot allocate MURAM memory for TxBDs\n");
- ret = -ENOMEM;
- goto free_rx_bd;
- }
- /* Alloc parameter ram for ucc hdlc */
- priv->ucc_pram_offset = qe_muram_alloc(sizeof(struct ucc_hdlc_param),
- ALIGNMENT_OF_UCC_HDLC_PRAM);
- if (priv->ucc_pram_offset < 0) {
- dev_err(priv->dev, "Can not allocate MURAM for hdlc parameter.\n");
- ret = -ENOMEM;
- goto free_tx_bd;
- }
- priv->rx_skbuff = kcalloc(priv->rx_ring_size,
- sizeof(*priv->rx_skbuff),
- GFP_KERNEL);
- if (!priv->rx_skbuff) {
- ret = -ENOMEM;
- goto free_ucc_pram;
- }
- priv->tx_skbuff = kcalloc(priv->tx_ring_size,
- sizeof(*priv->tx_skbuff),
- GFP_KERNEL);
- if (!priv->tx_skbuff) {
- ret = -ENOMEM;
- goto free_rx_skbuff;
- }
- priv->skb_curtx = 0;
- priv->skb_dirtytx = 0;
- priv->curtx_bd = priv->tx_bd_base;
- priv->dirty_tx = priv->tx_bd_base;
- priv->currx_bd = priv->rx_bd_base;
- priv->currx_bdnum = 0;
- /* init parameter base */
- cecr_subblock = ucc_fast_get_qe_cr_subblock(uf_info->ucc_num);
- ret = qe_issue_cmd(QE_ASSIGN_PAGE_TO_DEVICE, cecr_subblock,
- QE_CR_PROTOCOL_UNSPECIFIED, priv->ucc_pram_offset);
- priv->ucc_pram = (struct ucc_hdlc_param __iomem *)
- qe_muram_addr(priv->ucc_pram_offset);
- /* Zero out parameter ram */
- memset_io(priv->ucc_pram, 0, sizeof(struct ucc_hdlc_param));
- /* Alloc riptr, tiptr */
- riptr = qe_muram_alloc(32, 32);
- if (riptr < 0) {
- dev_err(priv->dev, "Cannot allocate MURAM mem for Receive internal temp data pointer\n");
- ret = -ENOMEM;
- goto free_tx_skbuff;
- }
- tiptr = qe_muram_alloc(32, 32);
- if (tiptr < 0) {
- dev_err(priv->dev, "Cannot allocate MURAM mem for Transmit internal temp data pointer\n");
- ret = -ENOMEM;
- goto free_riptr;
- }
- if (riptr != (u16)riptr || tiptr != (u16)tiptr) {
- dev_err(priv->dev, "MURAM allocation out of addressable range\n");
- ret = -ENOMEM;
- goto free_tiptr;
- }
- /* Set RIPTR, TIPTR */
- iowrite16be(riptr, &priv->ucc_pram->riptr);
- iowrite16be(tiptr, &priv->ucc_pram->tiptr);
- /* Set MRBLR */
- iowrite16be(MAX_RX_BUF_LENGTH, &priv->ucc_pram->mrblr);
- /* Set RBASE, TBASE */
- iowrite32be(priv->dma_rx_bd, &priv->ucc_pram->rbase);
- iowrite32be(priv->dma_tx_bd, &priv->ucc_pram->tbase);
- /* Set RSTATE, TSTATE */
- iowrite32be(BMR_GBL | BMR_BIG_ENDIAN, &priv->ucc_pram->rstate);
- iowrite32be(BMR_GBL | BMR_BIG_ENDIAN, &priv->ucc_pram->tstate);
- /* Set C_MASK, C_PRES for 16bit CRC */
- iowrite32be(CRC_16BIT_MASK, &priv->ucc_pram->c_mask);
- iowrite32be(CRC_16BIT_PRES, &priv->ucc_pram->c_pres);
- iowrite16be(MAX_FRAME_LENGTH, &priv->ucc_pram->mflr);
- iowrite16be(DEFAULT_RFTHR, &priv->ucc_pram->rfthr);
- iowrite16be(DEFAULT_RFTHR, &priv->ucc_pram->rfcnt);
- iowrite16be(priv->hmask, &priv->ucc_pram->hmask);
- iowrite16be(DEFAULT_HDLC_ADDR, &priv->ucc_pram->haddr1);
- iowrite16be(DEFAULT_HDLC_ADDR, &priv->ucc_pram->haddr2);
- iowrite16be(DEFAULT_HDLC_ADDR, &priv->ucc_pram->haddr3);
- iowrite16be(DEFAULT_HDLC_ADDR, &priv->ucc_pram->haddr4);
- /* Get BD buffer */
- bd_buffer = dma_alloc_coherent(priv->dev,
- (RX_BD_RING_LEN + TX_BD_RING_LEN) * MAX_RX_BUF_LENGTH,
- &bd_dma_addr, GFP_KERNEL);
- if (!bd_buffer) {
- dev_err(priv->dev, "Could not allocate buffer descriptors\n");
- ret = -ENOMEM;
- goto free_tiptr;
- }
- priv->rx_buffer = bd_buffer;
- priv->tx_buffer = bd_buffer + RX_BD_RING_LEN * MAX_RX_BUF_LENGTH;
- priv->dma_rx_addr = bd_dma_addr;
- priv->dma_tx_addr = bd_dma_addr + RX_BD_RING_LEN * MAX_RX_BUF_LENGTH;
- for (i = 0; i < RX_BD_RING_LEN; i++) {
- if (i < (RX_BD_RING_LEN - 1))
- bd_status = R_E_S | R_I_S;
- else
- bd_status = R_E_S | R_I_S | R_W_S;
- priv->rx_bd_base[i].status = cpu_to_be16(bd_status);
- priv->rx_bd_base[i].buf = cpu_to_be32(priv->dma_rx_addr + i * MAX_RX_BUF_LENGTH);
- }
- for (i = 0; i < TX_BD_RING_LEN; i++) {
- if (i < (TX_BD_RING_LEN - 1))
- bd_status = T_I_S | T_TC_S;
- else
- bd_status = T_I_S | T_TC_S | T_W_S;
- priv->tx_bd_base[i].status = cpu_to_be16(bd_status);
- priv->tx_bd_base[i].buf = cpu_to_be32(priv->dma_tx_addr + i * MAX_RX_BUF_LENGTH);
- }
- dma_wmb();
- return 0;
- free_tiptr:
- qe_muram_free(tiptr);
- free_riptr:
- qe_muram_free(riptr);
- free_tx_skbuff:
- kfree(priv->tx_skbuff);
- free_rx_skbuff:
- kfree(priv->rx_skbuff);
- free_ucc_pram:
- qe_muram_free(priv->ucc_pram_offset);
- free_tx_bd:
- dma_free_coherent(priv->dev,
- TX_BD_RING_LEN * sizeof(struct qe_bd),
- priv->tx_bd_base, priv->dma_tx_bd);
- free_rx_bd:
- dma_free_coherent(priv->dev,
- RX_BD_RING_LEN * sizeof(struct qe_bd),
- priv->rx_bd_base, priv->dma_rx_bd);
- free_uccf:
- ucc_fast_free(priv->uccf);
- return ret;
- }
- static netdev_tx_t ucc_hdlc_tx(struct sk_buff *skb, struct net_device *dev)
- {
- hdlc_device *hdlc = dev_to_hdlc(dev);
- struct ucc_hdlc_private *priv = (struct ucc_hdlc_private *)hdlc->priv;
- struct qe_bd *bd;
- u16 bd_status;
- unsigned long flags;
- __be16 *proto_head;
- switch (dev->type) {
- case ARPHRD_RAWHDLC:
- if (skb_headroom(skb) < HDLC_HEAD_LEN) {
- dev->stats.tx_dropped++;
- dev_kfree_skb(skb);
- netdev_err(dev, "No enough space for hdlc head\n");
- return -ENOMEM;
- }
- skb_push(skb, HDLC_HEAD_LEN);
- proto_head = (__be16 *)skb->data;
- *proto_head = htons(DEFAULT_HDLC_HEAD);
- dev->stats.tx_bytes += skb->len;
- break;
- case ARPHRD_PPP:
- proto_head = (__be16 *)skb->data;
- if (*proto_head != htons(DEFAULT_PPP_HEAD)) {
- dev->stats.tx_dropped++;
- dev_kfree_skb(skb);
- netdev_err(dev, "Wrong ppp header\n");
- return -ENOMEM;
- }
- dev->stats.tx_bytes += skb->len;
- break;
- case ARPHRD_ETHER:
- dev->stats.tx_bytes += skb->len;
- break;
- default:
- dev->stats.tx_dropped++;
- dev_kfree_skb(skb);
- return -ENOMEM;
- }
- netdev_sent_queue(dev, skb->len);
- spin_lock_irqsave(&priv->lock, flags);
- dma_rmb();
- /* Start from the next BD that should be filled */
- bd = priv->curtx_bd;
- bd_status = be16_to_cpu(bd->status);
- /* Save the skb pointer so we can free it later */
- priv->tx_skbuff[priv->skb_curtx] = skb;
- /* Update the current skb pointer (wrapping if this was the last) */
- priv->skb_curtx =
- (priv->skb_curtx + 1) & TX_RING_MOD_MASK(TX_BD_RING_LEN);
- /* copy skb data to tx buffer for sdma processing */
- memcpy(priv->tx_buffer + (be32_to_cpu(bd->buf) - priv->dma_tx_addr),
- skb->data, skb->len);
- /* set bd status and length */
- bd_status = (bd_status & T_W_S) | T_R_S | T_I_S | T_L_S | T_TC_S;
- bd->length = cpu_to_be16(skb->len);
- bd->status = cpu_to_be16(bd_status);
- /* Move to next BD in the ring */
- if (!(bd_status & T_W_S))
- bd += 1;
- else
- bd = priv->tx_bd_base;
- if (bd == priv->dirty_tx) {
- if (!netif_queue_stopped(dev))
- netif_stop_queue(dev);
- }
- priv->curtx_bd = bd;
- spin_unlock_irqrestore(&priv->lock, flags);
- return NETDEV_TX_OK;
- }
- static int hdlc_tx_restart(struct ucc_hdlc_private *priv)
- {
- u32 cecr_subblock;
- cecr_subblock =
- ucc_fast_get_qe_cr_subblock(priv->ut_info->uf_info.ucc_num);
- qe_issue_cmd(QE_RESTART_TX, cecr_subblock,
- QE_CR_PROTOCOL_UNSPECIFIED, 0);
- return 0;
- }
- static int hdlc_tx_done(struct ucc_hdlc_private *priv)
- {
- /* Start from the next BD that should be filled */
- struct net_device *dev = priv->ndev;
- unsigned int bytes_sent = 0;
- int howmany = 0;
- struct qe_bd *bd; /* BD pointer */
- u16 bd_status;
- int tx_restart = 0;
- dma_rmb();
- bd = priv->dirty_tx;
- bd_status = be16_to_cpu(bd->status);
- /* Normal processing. */
- while ((bd_status & T_R_S) == 0) {
- struct sk_buff *skb;
- if (bd_status & T_UN_S) { /* Underrun */
- dev->stats.tx_fifo_errors++;
- tx_restart = 1;
- }
- if (bd_status & T_CT_S) { /* Carrier lost */
- dev->stats.tx_carrier_errors++;
- tx_restart = 1;
- }
- /* BD contains already transmitted buffer. */
- /* Handle the transmitted buffer and release */
- /* the BD to be used with the current frame */
- skb = priv->tx_skbuff[priv->skb_dirtytx];
- if (!skb)
- break;
- howmany++;
- bytes_sent += skb->len;
- dev->stats.tx_packets++;
- memset(priv->tx_buffer +
- (be32_to_cpu(bd->buf) - priv->dma_tx_addr),
- 0, skb->len);
- dev_consume_skb_irq(skb);
- priv->tx_skbuff[priv->skb_dirtytx] = NULL;
- priv->skb_dirtytx =
- (priv->skb_dirtytx +
- 1) & TX_RING_MOD_MASK(TX_BD_RING_LEN);
- /* We freed a buffer, so now we can restart transmission */
- if (netif_queue_stopped(dev))
- netif_wake_queue(dev);
- /* Advance the confirmation BD pointer */
- if (!(bd_status & T_W_S))
- bd += 1;
- else
- bd = priv->tx_bd_base;
- bd_status = be16_to_cpu(bd->status);
- }
- priv->dirty_tx = bd;
- if (tx_restart)
- hdlc_tx_restart(priv);
- netdev_completed_queue(dev, howmany, bytes_sent);
- return 0;
- }
- static int hdlc_rx_done(struct ucc_hdlc_private *priv, int rx_work_limit)
- {
- struct net_device *dev = priv->ndev;
- struct sk_buff *skb = NULL;
- hdlc_device *hdlc = dev_to_hdlc(dev);
- struct qe_bd *bd;
- u16 bd_status;
- u16 length, howmany = 0;
- u8 *bdbuffer;
- dma_rmb();
- bd = priv->currx_bd;
- bd_status = be16_to_cpu(bd->status);
- /* while there are received buffers and BD is full (~R_E) */
- while (!((bd_status & (R_E_S)) || (--rx_work_limit < 0))) {
- if (bd_status & (RX_BD_ERRORS)) {
- dev->stats.rx_errors++;
- if (bd_status & R_CD_S)
- dev->stats.collisions++;
- if (bd_status & R_OV_S)
- dev->stats.rx_fifo_errors++;
- if (bd_status & R_CR_S)
- dev->stats.rx_crc_errors++;
- if (bd_status & R_AB_S)
- dev->stats.rx_over_errors++;
- if (bd_status & R_NO_S)
- dev->stats.rx_frame_errors++;
- if (bd_status & R_LG_S)
- dev->stats.rx_length_errors++;
- goto recycle;
- }
- bdbuffer = priv->rx_buffer +
- (priv->currx_bdnum * MAX_RX_BUF_LENGTH);
- length = be16_to_cpu(bd->length);
- switch (dev->type) {
- case ARPHRD_RAWHDLC:
- bdbuffer += HDLC_HEAD_LEN;
- length -= (HDLC_HEAD_LEN + HDLC_CRC_SIZE);
- skb = dev_alloc_skb(length);
- if (!skb) {
- dev->stats.rx_dropped++;
- return -ENOMEM;
- }
- skb_put(skb, length);
- skb->len = length;
- skb->dev = dev;
- memcpy(skb->data, bdbuffer, length);
- break;
- case ARPHRD_PPP:
- case ARPHRD_ETHER:
- length -= HDLC_CRC_SIZE;
- skb = dev_alloc_skb(length);
- if (!skb) {
- dev->stats.rx_dropped++;
- return -ENOMEM;
- }
- skb_put(skb, length);
- skb->len = length;
- skb->dev = dev;
- memcpy(skb->data, bdbuffer, length);
- break;
- }
- dev->stats.rx_packets++;
- dev->stats.rx_bytes += skb->len;
- howmany++;
- if (hdlc->proto)
- skb->protocol = hdlc_type_trans(skb, dev);
- netif_receive_skb(skb);
- recycle:
- bd->status = cpu_to_be16((bd_status & R_W_S) | R_E_S | R_I_S);
- /* update to point at the next bd */
- if (bd_status & R_W_S) {
- priv->currx_bdnum = 0;
- bd = priv->rx_bd_base;
- } else {
- if (priv->currx_bdnum < (RX_BD_RING_LEN - 1))
- priv->currx_bdnum += 1;
- else
- priv->currx_bdnum = RX_BD_RING_LEN - 1;
- bd += 1;
- }
- bd_status = be16_to_cpu(bd->status);
- }
- dma_rmb();
- priv->currx_bd = bd;
- return howmany;
- }
- static int ucc_hdlc_poll(struct napi_struct *napi, int budget)
- {
- struct ucc_hdlc_private *priv = container_of(napi,
- struct ucc_hdlc_private,
- napi);
- int howmany;
- /* Tx event processing */
- spin_lock(&priv->lock);
- hdlc_tx_done(priv);
- spin_unlock(&priv->lock);
- howmany = 0;
- howmany += hdlc_rx_done(priv, budget - howmany);
- if (howmany < budget) {
- napi_complete_done(napi, howmany);
- qe_setbits_be32(priv->uccf->p_uccm,
- (UCCE_HDLC_RX_EVENTS | UCCE_HDLC_TX_EVENTS) << 16);
- }
- return howmany;
- }
- static irqreturn_t ucc_hdlc_irq_handler(int irq, void *dev_id)
- {
- struct ucc_hdlc_private *priv = (struct ucc_hdlc_private *)dev_id;
- struct net_device *dev = priv->ndev;
- struct ucc_fast_private *uccf;
- u32 ucce;
- u32 uccm;
- uccf = priv->uccf;
- ucce = ioread32be(uccf->p_ucce);
- uccm = ioread32be(uccf->p_uccm);
- ucce &= uccm;
- iowrite32be(ucce, uccf->p_ucce);
- if (!ucce)
- return IRQ_NONE;
- if ((ucce >> 16) & (UCCE_HDLC_RX_EVENTS | UCCE_HDLC_TX_EVENTS)) {
- if (napi_schedule_prep(&priv->napi)) {
- uccm &= ~((UCCE_HDLC_RX_EVENTS | UCCE_HDLC_TX_EVENTS)
- << 16);
- iowrite32be(uccm, uccf->p_uccm);
- __napi_schedule(&priv->napi);
- }
- }
- /* Errors and other events */
- if (ucce >> 16 & UCC_HDLC_UCCE_BSY)
- dev->stats.rx_missed_errors++;
- if (ucce >> 16 & UCC_HDLC_UCCE_TXE)
- dev->stats.tx_errors++;
- return IRQ_HANDLED;
- }
- static int uhdlc_ioctl(struct net_device *dev, struct if_settings *ifs)
- {
- const size_t size = sizeof(te1_settings);
- te1_settings line;
- struct ucc_hdlc_private *priv = netdev_priv(dev);
- switch (ifs->type) {
- case IF_GET_IFACE:
- ifs->type = IF_IFACE_E1;
- if (ifs->size < size) {
- ifs->size = size; /* data size wanted */
- return -ENOBUFS;
- }
- memset(&line, 0, sizeof(line));
- line.clock_type = priv->clocking;
- if (copy_to_user(ifs->ifs_ifsu.sync, &line, size))
- return -EFAULT;
- return 0;
- default:
- return hdlc_ioctl(dev, ifs);
- }
- }
- static int uhdlc_open(struct net_device *dev)
- {
- u32 cecr_subblock;
- hdlc_device *hdlc = dev_to_hdlc(dev);
- struct ucc_hdlc_private *priv = hdlc->priv;
- struct ucc_tdm *utdm = priv->utdm;
- int rc = 0;
- if (priv->hdlc_busy != 1) {
- if (request_irq(priv->ut_info->uf_info.irq,
- ucc_hdlc_irq_handler, 0, "hdlc", priv))
- return -ENODEV;
- cecr_subblock = ucc_fast_get_qe_cr_subblock(
- priv->ut_info->uf_info.ucc_num);
- qe_issue_cmd(QE_INIT_TX_RX, cecr_subblock,
- QE_CR_PROTOCOL_UNSPECIFIED, 0);
- ucc_fast_enable(priv->uccf, COMM_DIR_RX | COMM_DIR_TX);
- /* Enable the TDM port */
- if (priv->tsa)
- qe_setbits_8(&utdm->si_regs->siglmr1_h, 0x1 << utdm->tdm_port);
- priv->hdlc_busy = 1;
- netif_device_attach(priv->ndev);
- napi_enable(&priv->napi);
- netdev_reset_queue(dev);
- netif_start_queue(dev);
- rc = hdlc_open(dev);
- if (rc)
- uhdlc_close(dev);
- }
- return rc;
- }
- static void uhdlc_memclean(struct ucc_hdlc_private *priv)
- {
- qe_muram_free(ioread16be(&priv->ucc_pram->riptr));
- qe_muram_free(ioread16be(&priv->ucc_pram->tiptr));
- if (priv->rx_bd_base) {
- dma_free_coherent(priv->dev,
- RX_BD_RING_LEN * sizeof(struct qe_bd),
- priv->rx_bd_base, priv->dma_rx_bd);
- priv->rx_bd_base = NULL;
- priv->dma_rx_bd = 0;
- }
- if (priv->tx_bd_base) {
- dma_free_coherent(priv->dev,
- TX_BD_RING_LEN * sizeof(struct qe_bd),
- priv->tx_bd_base, priv->dma_tx_bd);
- priv->tx_bd_base = NULL;
- priv->dma_tx_bd = 0;
- }
- if (priv->ucc_pram) {
- qe_muram_free(priv->ucc_pram_offset);
- priv->ucc_pram = NULL;
- priv->ucc_pram_offset = 0;
- }
- kfree(priv->rx_skbuff);
- priv->rx_skbuff = NULL;
- kfree(priv->tx_skbuff);
- priv->tx_skbuff = NULL;
- if (priv->uf_regs) {
- iounmap(priv->uf_regs);
- priv->uf_regs = NULL;
- }
- if (priv->uccf) {
- ucc_fast_free(priv->uccf);
- priv->uccf = NULL;
- }
- if (priv->rx_buffer) {
- dma_free_coherent(priv->dev,
- RX_BD_RING_LEN * MAX_RX_BUF_LENGTH,
- priv->rx_buffer, priv->dma_rx_addr);
- priv->rx_buffer = NULL;
- priv->dma_rx_addr = 0;
- }
- if (priv->tx_buffer) {
- dma_free_coherent(priv->dev,
- TX_BD_RING_LEN * MAX_RX_BUF_LENGTH,
- priv->tx_buffer, priv->dma_tx_addr);
- priv->tx_buffer = NULL;
- priv->dma_tx_addr = 0;
- }
- }
- static int uhdlc_close(struct net_device *dev)
- {
- struct ucc_hdlc_private *priv = dev_to_hdlc(dev)->priv;
- struct ucc_tdm *utdm = priv->utdm;
- u32 cecr_subblock;
- napi_disable(&priv->napi);
- cecr_subblock = ucc_fast_get_qe_cr_subblock(
- priv->ut_info->uf_info.ucc_num);
- qe_issue_cmd(QE_GRACEFUL_STOP_TX, cecr_subblock,
- (u8)QE_CR_PROTOCOL_UNSPECIFIED, 0);
- qe_issue_cmd(QE_CLOSE_RX_BD, cecr_subblock,
- (u8)QE_CR_PROTOCOL_UNSPECIFIED, 0);
- if (priv->tsa)
- qe_clrbits_8(&utdm->si_regs->siglmr1_h, 0x1 << utdm->tdm_port);
- ucc_fast_disable(priv->uccf, COMM_DIR_RX | COMM_DIR_TX);
- free_irq(priv->ut_info->uf_info.irq, priv);
- netif_stop_queue(dev);
- netdev_reset_queue(dev);
- priv->hdlc_busy = 0;
- hdlc_close(dev);
- return 0;
- }
- static int ucc_hdlc_attach(struct net_device *dev, unsigned short encoding,
- unsigned short parity)
- {
- struct ucc_hdlc_private *priv = dev_to_hdlc(dev)->priv;
- if (encoding != ENCODING_NRZ &&
- encoding != ENCODING_NRZI)
- return -EINVAL;
- if (parity != PARITY_NONE &&
- parity != PARITY_CRC32_PR1_CCITT &&
- parity != PARITY_CRC16_PR0_CCITT &&
- parity != PARITY_CRC16_PR1_CCITT)
- return -EINVAL;
- priv->encoding = encoding;
- priv->parity = parity;
- return 0;
- }
- #ifdef CONFIG_PM
- static void store_clk_config(struct ucc_hdlc_private *priv)
- {
- struct qe_mux __iomem *qe_mux_reg = &qe_immr->qmx;
- /* store si clk */
- priv->cmxsi1cr_h = ioread32be(&qe_mux_reg->cmxsi1cr_h);
- priv->cmxsi1cr_l = ioread32be(&qe_mux_reg->cmxsi1cr_l);
- /* store si sync */
- priv->cmxsi1syr = ioread32be(&qe_mux_reg->cmxsi1syr);
- /* store ucc clk */
- memcpy_fromio(priv->cmxucr, qe_mux_reg->cmxucr, 4 * sizeof(u32));
- }
- static void resume_clk_config(struct ucc_hdlc_private *priv)
- {
- struct qe_mux __iomem *qe_mux_reg = &qe_immr->qmx;
- memcpy_toio(qe_mux_reg->cmxucr, priv->cmxucr, 4 * sizeof(u32));
- iowrite32be(priv->cmxsi1cr_h, &qe_mux_reg->cmxsi1cr_h);
- iowrite32be(priv->cmxsi1cr_l, &qe_mux_reg->cmxsi1cr_l);
- iowrite32be(priv->cmxsi1syr, &qe_mux_reg->cmxsi1syr);
- }
- static int uhdlc_suspend(struct device *dev)
- {
- struct ucc_hdlc_private *priv = dev_get_drvdata(dev);
- struct ucc_fast __iomem *uf_regs;
- if (!priv)
- return -EINVAL;
- if (!netif_running(priv->ndev))
- return 0;
- netif_device_detach(priv->ndev);
- napi_disable(&priv->napi);
- uf_regs = priv->uf_regs;
- /* backup gumr guemr*/
- priv->gumr = ioread32be(&uf_regs->gumr);
- priv->guemr = ioread8(&uf_regs->guemr);
- priv->ucc_pram_bak = kmalloc(sizeof(*priv->ucc_pram_bak),
- GFP_KERNEL);
- if (!priv->ucc_pram_bak)
- return -ENOMEM;
- /* backup HDLC parameter */
- memcpy_fromio(priv->ucc_pram_bak, priv->ucc_pram,
- sizeof(struct ucc_hdlc_param));
- /* store the clk configuration */
- store_clk_config(priv);
- /* save power */
- ucc_fast_disable(priv->uccf, COMM_DIR_RX | COMM_DIR_TX);
- return 0;
- }
- static int uhdlc_resume(struct device *dev)
- {
- struct ucc_hdlc_private *priv = dev_get_drvdata(dev);
- struct ucc_tdm *utdm;
- struct ucc_tdm_info *ut_info;
- struct ucc_fast __iomem *uf_regs;
- struct ucc_fast_private *uccf;
- struct ucc_fast_info *uf_info;
- int i;
- u32 cecr_subblock;
- u16 bd_status;
- if (!priv)
- return -EINVAL;
- if (!netif_running(priv->ndev))
- return 0;
- utdm = priv->utdm;
- ut_info = priv->ut_info;
- uf_info = &ut_info->uf_info;
- uf_regs = priv->uf_regs;
- uccf = priv->uccf;
- /* restore gumr guemr */
- iowrite8(priv->guemr, &uf_regs->guemr);
- iowrite32be(priv->gumr, &uf_regs->gumr);
- /* Set Virtual Fifo registers */
- iowrite16be(uf_info->urfs, &uf_regs->urfs);
- iowrite16be(uf_info->urfet, &uf_regs->urfet);
- iowrite16be(uf_info->urfset, &uf_regs->urfset);
- iowrite16be(uf_info->utfs, &uf_regs->utfs);
- iowrite16be(uf_info->utfet, &uf_regs->utfet);
- iowrite16be(uf_info->utftt, &uf_regs->utftt);
- /* utfb, urfb are offsets from MURAM base */
- iowrite32be(uccf->ucc_fast_tx_virtual_fifo_base_offset, &uf_regs->utfb);
- iowrite32be(uccf->ucc_fast_rx_virtual_fifo_base_offset, &uf_regs->urfb);
- /* Rx Tx and sync clock routing */
- resume_clk_config(priv);
- iowrite32be(uf_info->uccm_mask, &uf_regs->uccm);
- iowrite32be(0xffffffff, &uf_regs->ucce);
- ucc_fast_disable(priv->uccf, COMM_DIR_RX | COMM_DIR_TX);
- /* rebuild SIRAM */
- if (priv->tsa)
- ucc_tdm_init(priv->utdm, priv->ut_info);
- /* Write to QE CECR, UCCx channel to Stop Transmission */
- cecr_subblock = ucc_fast_get_qe_cr_subblock(uf_info->ucc_num);
- qe_issue_cmd(QE_STOP_TX, cecr_subblock,
- (u8)QE_CR_PROTOCOL_UNSPECIFIED, 0);
- /* Set UPSMR normal mode */
- iowrite32be(0, &uf_regs->upsmr);
- /* init parameter base */
- cecr_subblock = ucc_fast_get_qe_cr_subblock(uf_info->ucc_num);
- qe_issue_cmd(QE_ASSIGN_PAGE_TO_DEVICE, cecr_subblock,
- QE_CR_PROTOCOL_UNSPECIFIED, priv->ucc_pram_offset);
- priv->ucc_pram = (struct ucc_hdlc_param __iomem *)
- qe_muram_addr(priv->ucc_pram_offset);
- /* restore ucc parameter */
- memcpy_toio(priv->ucc_pram, priv->ucc_pram_bak,
- sizeof(struct ucc_hdlc_param));
- kfree(priv->ucc_pram_bak);
- /* rebuild BD entry */
- for (i = 0; i < RX_BD_RING_LEN; i++) {
- if (i < (RX_BD_RING_LEN - 1))
- bd_status = R_E_S | R_I_S;
- else
- bd_status = R_E_S | R_I_S | R_W_S;
- priv->rx_bd_base[i].status = cpu_to_be16(bd_status);
- priv->rx_bd_base[i].buf = cpu_to_be32(priv->dma_rx_addr + i * MAX_RX_BUF_LENGTH);
- }
- for (i = 0; i < TX_BD_RING_LEN; i++) {
- if (i < (TX_BD_RING_LEN - 1))
- bd_status = T_I_S | T_TC_S;
- else
- bd_status = T_I_S | T_TC_S | T_W_S;
- priv->tx_bd_base[i].status = cpu_to_be16(bd_status);
- priv->tx_bd_base[i].buf = cpu_to_be32(priv->dma_tx_addr + i * MAX_RX_BUF_LENGTH);
- }
- dma_wmb();
- /* if hdlc is busy enable TX and RX */
- if (priv->hdlc_busy == 1) {
- cecr_subblock = ucc_fast_get_qe_cr_subblock(
- priv->ut_info->uf_info.ucc_num);
- qe_issue_cmd(QE_INIT_TX_RX, cecr_subblock,
- (u8)QE_CR_PROTOCOL_UNSPECIFIED, 0);
- ucc_fast_enable(priv->uccf, COMM_DIR_RX | COMM_DIR_TX);
- /* Enable the TDM port */
- if (priv->tsa)
- qe_setbits_8(&utdm->si_regs->siglmr1_h, 0x1 << utdm->tdm_port);
- }
- napi_enable(&priv->napi);
- netif_device_attach(priv->ndev);
- return 0;
- }
- static const struct dev_pm_ops uhdlc_pm_ops = {
- .suspend = uhdlc_suspend,
- .resume = uhdlc_resume,
- .freeze = uhdlc_suspend,
- .thaw = uhdlc_resume,
- };
- #define HDLC_PM_OPS (&uhdlc_pm_ops)
- #else
- #define HDLC_PM_OPS NULL
- #endif
- static void uhdlc_tx_timeout(struct net_device *ndev, unsigned int txqueue)
- {
- netdev_err(ndev, "%s\n", __func__);
- }
- static const struct net_device_ops uhdlc_ops = {
- .ndo_open = uhdlc_open,
- .ndo_stop = uhdlc_close,
- .ndo_start_xmit = hdlc_start_xmit,
- .ndo_siocwandev = uhdlc_ioctl,
- .ndo_tx_timeout = uhdlc_tx_timeout,
- };
- static int hdlc_map_iomem(char *name, int init_flag, void __iomem **ptr)
- {
- struct device_node *np;
- struct platform_device *pdev;
- struct resource *res;
- static int siram_init_flag;
- int ret = 0;
- np = of_find_compatible_node(NULL, NULL, name);
- if (!np)
- return -EINVAL;
- pdev = of_find_device_by_node(np);
- if (!pdev) {
- pr_err("%pOFn: failed to lookup pdev\n", np);
- of_node_put(np);
- return -EINVAL;
- }
- of_node_put(np);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- ret = -EINVAL;
- goto error_put_device;
- }
- *ptr = ioremap(res->start, resource_size(res));
- if (!*ptr) {
- ret = -ENOMEM;
- goto error_put_device;
- }
- /* We've remapped the addresses, and we don't need the device any
- * more, so we should release it.
- */
- put_device(&pdev->dev);
- if (init_flag && siram_init_flag == 0) {
- memset_io(*ptr, 0, resource_size(res));
- siram_init_flag = 1;
- }
- return 0;
- error_put_device:
- put_device(&pdev->dev);
- return ret;
- }
- static int ucc_hdlc_probe(struct platform_device *pdev)
- {
- struct device_node *np = pdev->dev.of_node;
- struct ucc_hdlc_private *uhdlc_priv = NULL;
- struct ucc_tdm_info *ut_info;
- struct ucc_tdm *utdm = NULL;
- struct resource res;
- struct net_device *dev;
- hdlc_device *hdlc;
- int ucc_num;
- const char *sprop;
- int ret;
- u32 val;
- ret = of_property_read_u32_index(np, "cell-index", 0, &val);
- if (ret) {
- dev_err(&pdev->dev, "Invalid ucc property\n");
- return -ENODEV;
- }
- ucc_num = val - 1;
- if (ucc_num > (UCC_MAX_NUM - 1) || ucc_num < 0) {
- dev_err(&pdev->dev, ": Invalid UCC num\n");
- return -EINVAL;
- }
- memcpy(&utdm_info[ucc_num], &utdm_primary_info,
- sizeof(utdm_primary_info));
- ut_info = &utdm_info[ucc_num];
- ut_info->uf_info.ucc_num = ucc_num;
- sprop = of_get_property(np, "rx-clock-name", NULL);
- if (sprop) {
- ut_info->uf_info.rx_clock = qe_clock_source(sprop);
- if ((ut_info->uf_info.rx_clock < QE_CLK_NONE) ||
- (ut_info->uf_info.rx_clock > QE_CLK24)) {
- dev_err(&pdev->dev, "Invalid rx-clock-name property\n");
- return -EINVAL;
- }
- } else {
- dev_err(&pdev->dev, "Invalid rx-clock-name property\n");
- return -EINVAL;
- }
- sprop = of_get_property(np, "tx-clock-name", NULL);
- if (sprop) {
- ut_info->uf_info.tx_clock = qe_clock_source(sprop);
- if ((ut_info->uf_info.tx_clock < QE_CLK_NONE) ||
- (ut_info->uf_info.tx_clock > QE_CLK24)) {
- dev_err(&pdev->dev, "Invalid tx-clock-name property\n");
- return -EINVAL;
- }
- } else {
- dev_err(&pdev->dev, "Invalid tx-clock-name property\n");
- return -EINVAL;
- }
- ret = of_address_to_resource(np, 0, &res);
- if (ret)
- return -EINVAL;
- ut_info->uf_info.regs = res.start;
- ut_info->uf_info.irq = irq_of_parse_and_map(np, 0);
- uhdlc_priv = kzalloc(sizeof(*uhdlc_priv), GFP_KERNEL);
- if (!uhdlc_priv)
- return -ENOMEM;
- dev_set_drvdata(&pdev->dev, uhdlc_priv);
- uhdlc_priv->dev = &pdev->dev;
- uhdlc_priv->ut_info = ut_info;
- if (of_get_property(np, "fsl,tdm-interface", NULL))
- uhdlc_priv->tsa = 1;
- if (of_get_property(np, "fsl,ucc-internal-loopback", NULL))
- uhdlc_priv->loopback = 1;
- if (of_get_property(np, "fsl,hdlc-bus", NULL))
- uhdlc_priv->hdlc_bus = 1;
- if (uhdlc_priv->tsa == 1) {
- utdm = kzalloc(sizeof(*utdm), GFP_KERNEL);
- if (!utdm) {
- ret = -ENOMEM;
- dev_err(&pdev->dev, "No mem to alloc ucc tdm data\n");
- goto free_uhdlc_priv;
- }
- uhdlc_priv->utdm = utdm;
- ret = ucc_of_parse_tdm(np, utdm, ut_info);
- if (ret)
- goto free_utdm;
- ret = hdlc_map_iomem("fsl,t1040-qe-si", 0,
- (void __iomem **)&utdm->si_regs);
- if (ret)
- goto free_utdm;
- ret = hdlc_map_iomem("fsl,t1040-qe-siram", 1,
- (void __iomem **)&utdm->siram);
- if (ret)
- goto unmap_si_regs;
- }
- if (of_property_read_u16(np, "fsl,hmask", &uhdlc_priv->hmask))
- uhdlc_priv->hmask = DEFAULT_ADDR_MASK;
- ret = uhdlc_init(uhdlc_priv);
- if (ret) {
- dev_err(&pdev->dev, "Failed to init uhdlc\n");
- goto undo_uhdlc_init;
- }
- dev = alloc_hdlcdev(uhdlc_priv);
- if (!dev) {
- ret = -ENOMEM;
- pr_err("ucc_hdlc: unable to allocate memory\n");
- goto undo_uhdlc_init;
- }
- uhdlc_priv->ndev = dev;
- hdlc = dev_to_hdlc(dev);
- dev->tx_queue_len = 16;
- dev->netdev_ops = &uhdlc_ops;
- dev->watchdog_timeo = 2 * HZ;
- hdlc->attach = ucc_hdlc_attach;
- hdlc->xmit = ucc_hdlc_tx;
- netif_napi_add_weight(dev, &uhdlc_priv->napi, ucc_hdlc_poll, 32);
- if (register_hdlc_device(dev)) {
- ret = -ENOBUFS;
- pr_err("ucc_hdlc: unable to register hdlc device\n");
- goto free_dev;
- }
- return 0;
- free_dev:
- free_netdev(dev);
- undo_uhdlc_init:
- if (utdm)
- iounmap(utdm->siram);
- unmap_si_regs:
- if (utdm)
- iounmap(utdm->si_regs);
- free_utdm:
- if (uhdlc_priv->tsa)
- kfree(utdm);
- free_uhdlc_priv:
- kfree(uhdlc_priv);
- return ret;
- }
- static int ucc_hdlc_remove(struct platform_device *pdev)
- {
- struct ucc_hdlc_private *priv = dev_get_drvdata(&pdev->dev);
- uhdlc_memclean(priv);
- if (priv->utdm->si_regs) {
- iounmap(priv->utdm->si_regs);
- priv->utdm->si_regs = NULL;
- }
- if (priv->utdm->siram) {
- iounmap(priv->utdm->siram);
- priv->utdm->siram = NULL;
- }
- kfree(priv);
- dev_info(&pdev->dev, "UCC based hdlc module removed\n");
- return 0;
- }
- static const struct of_device_id fsl_ucc_hdlc_of_match[] = {
- {
- .compatible = "fsl,ucc-hdlc",
- },
- {},
- };
- MODULE_DEVICE_TABLE(of, fsl_ucc_hdlc_of_match);
- static struct platform_driver ucc_hdlc_driver = {
- .probe = ucc_hdlc_probe,
- .remove = ucc_hdlc_remove,
- .driver = {
- .name = DRV_NAME,
- .pm = HDLC_PM_OPS,
- .of_match_table = fsl_ucc_hdlc_of_match,
- },
- };
- module_platform_driver(ucc_hdlc_driver);
- MODULE_LICENSE("GPL");
- MODULE_DESCRIPTION(DRV_DESC);
|