13178d58eSHerve Codina // SPDX-License-Identifier: GPL-2.0 23178d58eSHerve Codina /* 33178d58eSHerve Codina * QMC driver 43178d58eSHerve Codina * 53178d58eSHerve Codina * Copyright 2022 CS GROUP France 63178d58eSHerve Codina * 73178d58eSHerve Codina * Author: Herve Codina <herve.codina@bootlin.com> 83178d58eSHerve Codina */ 93178d58eSHerve Codina 103178d58eSHerve Codina #include <soc/fsl/qe/qmc.h> 113178d58eSHerve Codina #include <linux/dma-mapping.h> 123178d58eSHerve Codina #include <linux/hdlc.h> 133178d58eSHerve Codina #include <linux/interrupt.h> 143178d58eSHerve Codina #include <linux/io.h> 153178d58eSHerve Codina #include <linux/module.h> 163178d58eSHerve Codina #include <linux/of.h> 173178d58eSHerve Codina #include <linux/of_platform.h> 183178d58eSHerve Codina #include <linux/platform_device.h> 193178d58eSHerve Codina #include <linux/slab.h> 203178d58eSHerve Codina #include <soc/fsl/cpm.h> 213178d58eSHerve Codina #include <sysdev/fsl_soc.h> 223178d58eSHerve Codina #include "tsa.h" 233178d58eSHerve Codina 243178d58eSHerve Codina /* SCC general mode register high (32 bits) */ 253178d58eSHerve Codina #define SCC_GSMRL 0x00 263178d58eSHerve Codina #define SCC_GSMRL_ENR (1 << 5) 273178d58eSHerve Codina #define SCC_GSMRL_ENT (1 << 4) 283178d58eSHerve Codina #define SCC_GSMRL_MODE_QMC (0x0A << 0) 293178d58eSHerve Codina 303178d58eSHerve Codina /* SCC general mode register low (32 bits) */ 313178d58eSHerve Codina #define SCC_GSMRH 0x04 323178d58eSHerve Codina #define SCC_GSMRH_CTSS (1 << 7) 333178d58eSHerve Codina #define SCC_GSMRH_CDS (1 << 8) 343178d58eSHerve Codina #define SCC_GSMRH_CTSP (1 << 9) 353178d58eSHerve Codina #define SCC_GSMRH_CDP (1 << 10) 363178d58eSHerve Codina 373178d58eSHerve Codina /* SCC event register (16 bits) */ 383178d58eSHerve Codina #define SCC_SCCE 0x10 393178d58eSHerve Codina #define SCC_SCCE_IQOV (1 << 3) 403178d58eSHerve Codina #define SCC_SCCE_GINT (1 << 2) 413178d58eSHerve Codina #define SCC_SCCE_GUN (1 << 1) 423178d58eSHerve Codina #define SCC_SCCE_GOV (1 << 0) 433178d58eSHerve Codina 443178d58eSHerve Codina /* SCC mask register (16 bits) */ 453178d58eSHerve Codina #define SCC_SCCM 0x14 463178d58eSHerve Codina /* Multichannel base pointer (32 bits) */ 473178d58eSHerve Codina #define QMC_GBL_MCBASE 0x00 483178d58eSHerve Codina /* Multichannel controller state (16 bits) */ 493178d58eSHerve Codina #define QMC_GBL_QMCSTATE 0x04 503178d58eSHerve Codina /* Maximum receive buffer length (16 bits) */ 513178d58eSHerve Codina #define QMC_GBL_MRBLR 0x06 523178d58eSHerve Codina /* Tx time-slot assignment table pointer (16 bits) */ 533178d58eSHerve Codina #define QMC_GBL_TX_S_PTR 0x08 543178d58eSHerve Codina /* Rx pointer (16 bits) */ 553178d58eSHerve Codina #define QMC_GBL_RXPTR 0x0A 563178d58eSHerve Codina /* Global receive frame threshold (16 bits) */ 573178d58eSHerve Codina #define QMC_GBL_GRFTHR 0x0C 583178d58eSHerve Codina /* Global receive frame count (16 bits) */ 593178d58eSHerve Codina #define QMC_GBL_GRFCNT 0x0E 603178d58eSHerve Codina /* Multichannel interrupt base address (32 bits) */ 613178d58eSHerve Codina #define QMC_GBL_INTBASE 0x10 623178d58eSHerve Codina /* Multichannel interrupt pointer (32 bits) */ 633178d58eSHerve Codina #define QMC_GBL_INTPTR 0x14 643178d58eSHerve Codina /* Rx time-slot assignment table pointer (16 bits) */ 653178d58eSHerve Codina #define QMC_GBL_RX_S_PTR 0x18 663178d58eSHerve Codina /* Tx pointer (16 bits) */ 673178d58eSHerve Codina #define QMC_GBL_TXPTR 0x1A 683178d58eSHerve Codina /* CRC constant (32 bits) */ 693178d58eSHerve Codina #define QMC_GBL_C_MASK32 0x1C 703178d58eSHerve Codina /* Time slot assignment table Rx (32 x 16 bits) */ 713178d58eSHerve Codina #define QMC_GBL_TSATRX 0x20 723178d58eSHerve Codina /* Time slot assignment table Tx (32 x 16 bits) */ 733178d58eSHerve Codina #define QMC_GBL_TSATTX 0x60 743178d58eSHerve Codina /* CRC constant (16 bits) */ 753178d58eSHerve Codina #define QMC_GBL_C_MASK16 0xA0 763178d58eSHerve Codina 773178d58eSHerve Codina /* TSA entry (16bit entry in TSATRX and TSATTX) */ 783178d58eSHerve Codina #define QMC_TSA_VALID (1 << 15) 793178d58eSHerve Codina #define QMC_TSA_WRAP (1 << 14) 803178d58eSHerve Codina #define QMC_TSA_MASK (0x303F) 813178d58eSHerve Codina #define QMC_TSA_CHANNEL(x) ((x) << 6) 823178d58eSHerve Codina 833178d58eSHerve Codina /* Tx buffer descriptor base address (16 bits, offset from MCBASE) */ 843178d58eSHerve Codina #define QMC_SPE_TBASE 0x00 853178d58eSHerve Codina 863178d58eSHerve Codina /* Channel mode register (16 bits) */ 873178d58eSHerve Codina #define QMC_SPE_CHAMR 0x02 883178d58eSHerve Codina #define QMC_SPE_CHAMR_MODE_HDLC (1 << 15) 893178d58eSHerve Codina #define QMC_SPE_CHAMR_MODE_TRANSP ((0 << 15) | (1 << 13)) 903178d58eSHerve Codina #define QMC_SPE_CHAMR_ENT (1 << 12) 913178d58eSHerve Codina #define QMC_SPE_CHAMR_POL (1 << 8) 923178d58eSHerve Codina #define QMC_SPE_CHAMR_HDLC_IDLM (1 << 13) 933178d58eSHerve Codina #define QMC_SPE_CHAMR_HDLC_CRC (1 << 7) 943178d58eSHerve Codina #define QMC_SPE_CHAMR_HDLC_NOF (0x0f << 0) 953178d58eSHerve Codina #define QMC_SPE_CHAMR_TRANSP_RD (1 << 14) 963178d58eSHerve Codina #define QMC_SPE_CHAMR_TRANSP_SYNC (1 << 10) 973178d58eSHerve Codina 983178d58eSHerve Codina /* Tx internal state (32 bits) */ 993178d58eSHerve Codina #define QMC_SPE_TSTATE 0x04 1003178d58eSHerve Codina /* Tx buffer descriptor pointer (16 bits) */ 1013178d58eSHerve Codina #define QMC_SPE_TBPTR 0x0C 1023178d58eSHerve Codina /* Zero-insertion state (32 bits) */ 1033178d58eSHerve Codina #define QMC_SPE_ZISTATE 0x14 1043178d58eSHerve Codina /* Channel’s interrupt mask flags (16 bits) */ 1053178d58eSHerve Codina #define QMC_SPE_INTMSK 0x1C 1063178d58eSHerve Codina /* Rx buffer descriptor base address (16 bits, offset from MCBASE) */ 1073178d58eSHerve Codina #define QMC_SPE_RBASE 0x20 1083178d58eSHerve Codina /* HDLC: Maximum frame length register (16 bits) */ 1093178d58eSHerve Codina #define QMC_SPE_MFLR 0x22 1103178d58eSHerve Codina /* TRANSPARENT: Transparent maximum receive length (16 bits) */ 1113178d58eSHerve Codina #define QMC_SPE_TMRBLR 0x22 1123178d58eSHerve Codina /* Rx internal state (32 bits) */ 1133178d58eSHerve Codina #define QMC_SPE_RSTATE 0x24 1143178d58eSHerve Codina /* Rx buffer descriptor pointer (16 bits) */ 1153178d58eSHerve Codina #define QMC_SPE_RBPTR 0x2C 1163178d58eSHerve Codina /* Packs 4 bytes to 1 long word before writing to buffer (32 bits) */ 1173178d58eSHerve Codina #define QMC_SPE_RPACK 0x30 1183178d58eSHerve Codina /* Zero deletion state (32 bits) */ 1193178d58eSHerve Codina #define QMC_SPE_ZDSTATE 0x34 1203178d58eSHerve Codina 1213178d58eSHerve Codina /* Transparent synchronization (16 bits) */ 1223178d58eSHerve Codina #define QMC_SPE_TRNSYNC 0x3C 1233178d58eSHerve Codina #define QMC_SPE_TRNSYNC_RX(x) ((x) << 8) 1243178d58eSHerve Codina #define QMC_SPE_TRNSYNC_TX(x) ((x) << 0) 1253178d58eSHerve Codina 1263178d58eSHerve Codina /* Interrupt related registers bits */ 1273178d58eSHerve Codina #define QMC_INT_V (1 << 15) 1283178d58eSHerve Codina #define QMC_INT_W (1 << 14) 1293178d58eSHerve Codina #define QMC_INT_NID (1 << 13) 1303178d58eSHerve Codina #define QMC_INT_IDL (1 << 12) 1313178d58eSHerve Codina #define QMC_INT_GET_CHANNEL(x) (((x) & 0x0FC0) >> 6) 1323178d58eSHerve Codina #define QMC_INT_MRF (1 << 5) 1333178d58eSHerve Codina #define QMC_INT_UN (1 << 4) 1343178d58eSHerve Codina #define QMC_INT_RXF (1 << 3) 1353178d58eSHerve Codina #define QMC_INT_BSY (1 << 2) 1363178d58eSHerve Codina #define QMC_INT_TXB (1 << 1) 1373178d58eSHerve Codina #define QMC_INT_RXB (1 << 0) 1383178d58eSHerve Codina 1393178d58eSHerve Codina /* BD related registers bits */ 1403178d58eSHerve Codina #define QMC_BD_RX_E (1 << 15) 1413178d58eSHerve Codina #define QMC_BD_RX_W (1 << 13) 1423178d58eSHerve Codina #define QMC_BD_RX_I (1 << 12) 1433178d58eSHerve Codina #define QMC_BD_RX_L (1 << 11) 1443178d58eSHerve Codina #define QMC_BD_RX_F (1 << 10) 1453178d58eSHerve Codina #define QMC_BD_RX_CM (1 << 9) 1463178d58eSHerve Codina #define QMC_BD_RX_UB (1 << 7) 1473178d58eSHerve Codina #define QMC_BD_RX_LG (1 << 5) 1483178d58eSHerve Codina #define QMC_BD_RX_NO (1 << 4) 1493178d58eSHerve Codina #define QMC_BD_RX_AB (1 << 3) 1503178d58eSHerve Codina #define QMC_BD_RX_CR (1 << 2) 1513178d58eSHerve Codina 1523178d58eSHerve Codina #define QMC_BD_TX_R (1 << 15) 1533178d58eSHerve Codina #define QMC_BD_TX_W (1 << 13) 1543178d58eSHerve Codina #define QMC_BD_TX_I (1 << 12) 1553178d58eSHerve Codina #define QMC_BD_TX_L (1 << 11) 1563178d58eSHerve Codina #define QMC_BD_TX_TC (1 << 10) 1573178d58eSHerve Codina #define QMC_BD_TX_CM (1 << 9) 1583178d58eSHerve Codina #define QMC_BD_TX_UB (1 << 7) 1593178d58eSHerve Codina #define QMC_BD_TX_PAD (0x0f << 0) 1603178d58eSHerve Codina 1613178d58eSHerve Codina /* Numbers of BDs and interrupt items */ 1623178d58eSHerve Codina #define QMC_NB_TXBDS 8 1633178d58eSHerve Codina #define QMC_NB_RXBDS 8 1643178d58eSHerve Codina #define QMC_NB_INTS 128 1653178d58eSHerve Codina 1663178d58eSHerve Codina struct qmc_xfer_desc { 1673178d58eSHerve Codina union { 1683178d58eSHerve Codina void (*tx_complete)(void *context); 1693178d58eSHerve Codina void (*rx_complete)(void *context, size_t length); 1703178d58eSHerve Codina }; 1713178d58eSHerve Codina void *context; 1723178d58eSHerve Codina }; 1733178d58eSHerve Codina 1743178d58eSHerve Codina struct qmc_chan { 1753178d58eSHerve Codina struct list_head list; 1763178d58eSHerve Codina unsigned int id; 1773178d58eSHerve Codina struct qmc *qmc; 178*07d45e91SHerve Codina void __iomem *s_param; 1793178d58eSHerve Codina enum qmc_mode mode; 1803178d58eSHerve Codina u64 tx_ts_mask; 1813178d58eSHerve Codina u64 rx_ts_mask; 1823178d58eSHerve Codina bool is_reverse_data; 1833178d58eSHerve Codina 1843178d58eSHerve Codina spinlock_t tx_lock; 1853178d58eSHerve Codina cbd_t __iomem *txbds; 1863178d58eSHerve Codina cbd_t __iomem *txbd_free; 1873178d58eSHerve Codina cbd_t __iomem *txbd_done; 1883178d58eSHerve Codina struct qmc_xfer_desc tx_desc[QMC_NB_TXBDS]; 1893178d58eSHerve Codina u64 nb_tx_underrun; 1903178d58eSHerve Codina bool is_tx_stopped; 1913178d58eSHerve Codina 1923178d58eSHerve Codina spinlock_t rx_lock; 1933178d58eSHerve Codina cbd_t __iomem *rxbds; 1943178d58eSHerve Codina cbd_t __iomem *rxbd_free; 1953178d58eSHerve Codina cbd_t __iomem *rxbd_done; 1963178d58eSHerve Codina struct qmc_xfer_desc rx_desc[QMC_NB_RXBDS]; 1973178d58eSHerve Codina u64 nb_rx_busy; 1983178d58eSHerve Codina int rx_pending; 1993178d58eSHerve Codina bool is_rx_halted; 2003178d58eSHerve Codina bool is_rx_stopped; 2013178d58eSHerve Codina }; 2023178d58eSHerve Codina 2033178d58eSHerve Codina struct qmc { 2043178d58eSHerve Codina struct device *dev; 2053178d58eSHerve Codina struct tsa_serial *tsa_serial; 206*07d45e91SHerve Codina void __iomem *scc_regs; 207*07d45e91SHerve Codina void __iomem *scc_pram; 208*07d45e91SHerve Codina void __iomem *dpram; 2093178d58eSHerve Codina u16 scc_pram_offset; 2103178d58eSHerve Codina cbd_t __iomem *bd_table; 2113178d58eSHerve Codina dma_addr_t bd_dma_addr; 2123178d58eSHerve Codina size_t bd_size; 2133178d58eSHerve Codina u16 __iomem *int_table; 2143178d58eSHerve Codina u16 __iomem *int_curr; 2153178d58eSHerve Codina dma_addr_t int_dma_addr; 2163178d58eSHerve Codina size_t int_size; 2173178d58eSHerve Codina struct list_head chan_head; 2183178d58eSHerve Codina struct qmc_chan *chans[64]; 2193178d58eSHerve Codina }; 2203178d58eSHerve Codina 221*07d45e91SHerve Codina static inline void qmc_write16(void __iomem *addr, u16 val) 2223178d58eSHerve Codina { 2233178d58eSHerve Codina iowrite16be(val, addr); 2243178d58eSHerve Codina } 2253178d58eSHerve Codina 226*07d45e91SHerve Codina static inline u16 qmc_read16(void __iomem *addr) 2273178d58eSHerve Codina { 2283178d58eSHerve Codina return ioread16be(addr); 2293178d58eSHerve Codina } 2303178d58eSHerve Codina 231*07d45e91SHerve Codina static inline void qmc_setbits16(void __iomem *addr, u16 set) 2323178d58eSHerve Codina { 2333178d58eSHerve Codina qmc_write16(addr, qmc_read16(addr) | set); 2343178d58eSHerve Codina } 2353178d58eSHerve Codina 236*07d45e91SHerve Codina static inline void qmc_clrbits16(void __iomem *addr, u16 clr) 2373178d58eSHerve Codina { 2383178d58eSHerve Codina qmc_write16(addr, qmc_read16(addr) & ~clr); 2393178d58eSHerve Codina } 2403178d58eSHerve Codina 241*07d45e91SHerve Codina static inline void qmc_write32(void __iomem *addr, u32 val) 2423178d58eSHerve Codina { 2433178d58eSHerve Codina iowrite32be(val, addr); 2443178d58eSHerve Codina } 2453178d58eSHerve Codina 246*07d45e91SHerve Codina static inline u32 qmc_read32(void __iomem *addr) 2473178d58eSHerve Codina { 2483178d58eSHerve Codina return ioread32be(addr); 2493178d58eSHerve Codina } 2503178d58eSHerve Codina 251*07d45e91SHerve Codina static inline void qmc_setbits32(void __iomem *addr, u32 set) 2523178d58eSHerve Codina { 2533178d58eSHerve Codina qmc_write32(addr, qmc_read32(addr) | set); 2543178d58eSHerve Codina } 2553178d58eSHerve Codina 2563178d58eSHerve Codina 2573178d58eSHerve Codina int qmc_chan_get_info(struct qmc_chan *chan, struct qmc_chan_info *info) 2583178d58eSHerve Codina { 2593178d58eSHerve Codina struct tsa_serial_info tsa_info; 2603178d58eSHerve Codina int ret; 2613178d58eSHerve Codina 2623178d58eSHerve Codina /* Retrieve info from the TSA related serial */ 2633178d58eSHerve Codina ret = tsa_serial_get_info(chan->qmc->tsa_serial, &tsa_info); 2643178d58eSHerve Codina if (ret) 2653178d58eSHerve Codina return ret; 2663178d58eSHerve Codina 2673178d58eSHerve Codina info->mode = chan->mode; 2683178d58eSHerve Codina info->rx_fs_rate = tsa_info.rx_fs_rate; 2693178d58eSHerve Codina info->rx_bit_rate = tsa_info.rx_bit_rate; 2703178d58eSHerve Codina info->nb_tx_ts = hweight64(chan->tx_ts_mask); 2713178d58eSHerve Codina info->tx_fs_rate = tsa_info.tx_fs_rate; 2723178d58eSHerve Codina info->tx_bit_rate = tsa_info.tx_bit_rate; 2733178d58eSHerve Codina info->nb_rx_ts = hweight64(chan->rx_ts_mask); 2743178d58eSHerve Codina 2753178d58eSHerve Codina return 0; 2763178d58eSHerve Codina } 2773178d58eSHerve Codina EXPORT_SYMBOL(qmc_chan_get_info); 2783178d58eSHerve Codina 2793178d58eSHerve Codina int qmc_chan_set_param(struct qmc_chan *chan, const struct qmc_chan_param *param) 2803178d58eSHerve Codina { 2813178d58eSHerve Codina if (param->mode != chan->mode) 2823178d58eSHerve Codina return -EINVAL; 2833178d58eSHerve Codina 2843178d58eSHerve Codina switch (param->mode) { 2853178d58eSHerve Codina case QMC_HDLC: 2863178d58eSHerve Codina if ((param->hdlc.max_rx_buf_size % 4) || 2873178d58eSHerve Codina (param->hdlc.max_rx_buf_size < 8)) 2883178d58eSHerve Codina return -EINVAL; 2893178d58eSHerve Codina 2903178d58eSHerve Codina qmc_write16(chan->qmc->scc_pram + QMC_GBL_MRBLR, 2913178d58eSHerve Codina param->hdlc.max_rx_buf_size - 8); 2923178d58eSHerve Codina qmc_write16(chan->s_param + QMC_SPE_MFLR, 2933178d58eSHerve Codina param->hdlc.max_rx_frame_size); 2943178d58eSHerve Codina if (param->hdlc.is_crc32) { 2953178d58eSHerve Codina qmc_setbits16(chan->s_param + QMC_SPE_CHAMR, 2963178d58eSHerve Codina QMC_SPE_CHAMR_HDLC_CRC); 2973178d58eSHerve Codina } else { 2983178d58eSHerve Codina qmc_clrbits16(chan->s_param + QMC_SPE_CHAMR, 2993178d58eSHerve Codina QMC_SPE_CHAMR_HDLC_CRC); 3003178d58eSHerve Codina } 3013178d58eSHerve Codina break; 3023178d58eSHerve Codina 3033178d58eSHerve Codina case QMC_TRANSPARENT: 3043178d58eSHerve Codina qmc_write16(chan->s_param + QMC_SPE_TMRBLR, 3053178d58eSHerve Codina param->transp.max_rx_buf_size); 3063178d58eSHerve Codina break; 3073178d58eSHerve Codina 3083178d58eSHerve Codina default: 3093178d58eSHerve Codina return -EINVAL; 3103178d58eSHerve Codina } 3113178d58eSHerve Codina 3123178d58eSHerve Codina return 0; 3133178d58eSHerve Codina } 3143178d58eSHerve Codina EXPORT_SYMBOL(qmc_chan_set_param); 3153178d58eSHerve Codina 3163178d58eSHerve Codina int qmc_chan_write_submit(struct qmc_chan *chan, dma_addr_t addr, size_t length, 3173178d58eSHerve Codina void (*complete)(void *context), void *context) 3183178d58eSHerve Codina { 3193178d58eSHerve Codina struct qmc_xfer_desc *xfer_desc; 3203178d58eSHerve Codina unsigned long flags; 321*07d45e91SHerve Codina cbd_t __iomem *bd; 3223178d58eSHerve Codina u16 ctrl; 3233178d58eSHerve Codina int ret; 3243178d58eSHerve Codina 3253178d58eSHerve Codina /* 3263178d58eSHerve Codina * R bit UB bit 3273178d58eSHerve Codina * 0 0 : The BD is free 3283178d58eSHerve Codina * 1 1 : The BD is in used, waiting for transfer 3293178d58eSHerve Codina * 0 1 : The BD is in used, waiting for completion 3303178d58eSHerve Codina * 1 0 : Should not append 3313178d58eSHerve Codina */ 3323178d58eSHerve Codina 3333178d58eSHerve Codina spin_lock_irqsave(&chan->tx_lock, flags); 3343178d58eSHerve Codina bd = chan->txbd_free; 3353178d58eSHerve Codina 3363178d58eSHerve Codina ctrl = qmc_read16(&bd->cbd_sc); 3373178d58eSHerve Codina if (ctrl & (QMC_BD_TX_R | QMC_BD_TX_UB)) { 3383178d58eSHerve Codina /* We are full ... */ 3393178d58eSHerve Codina ret = -EBUSY; 3403178d58eSHerve Codina goto end; 3413178d58eSHerve Codina } 3423178d58eSHerve Codina 3433178d58eSHerve Codina qmc_write16(&bd->cbd_datlen, length); 3443178d58eSHerve Codina qmc_write32(&bd->cbd_bufaddr, addr); 3453178d58eSHerve Codina 3463178d58eSHerve Codina xfer_desc = &chan->tx_desc[bd - chan->txbds]; 3473178d58eSHerve Codina xfer_desc->tx_complete = complete; 3483178d58eSHerve Codina xfer_desc->context = context; 3493178d58eSHerve Codina 3503178d58eSHerve Codina /* Activate the descriptor */ 3513178d58eSHerve Codina ctrl |= (QMC_BD_TX_R | QMC_BD_TX_UB); 3523178d58eSHerve Codina wmb(); /* Be sure to flush the descriptor before control update */ 3533178d58eSHerve Codina qmc_write16(&bd->cbd_sc, ctrl); 3543178d58eSHerve Codina 3553178d58eSHerve Codina if (!chan->is_tx_stopped) 3563178d58eSHerve Codina qmc_setbits16(chan->s_param + QMC_SPE_CHAMR, QMC_SPE_CHAMR_POL); 3573178d58eSHerve Codina 3583178d58eSHerve Codina if (ctrl & QMC_BD_TX_W) 3593178d58eSHerve Codina chan->txbd_free = chan->txbds; 3603178d58eSHerve Codina else 3613178d58eSHerve Codina chan->txbd_free++; 3623178d58eSHerve Codina 3633178d58eSHerve Codina ret = 0; 3643178d58eSHerve Codina 3653178d58eSHerve Codina end: 3663178d58eSHerve Codina spin_unlock_irqrestore(&chan->tx_lock, flags); 3673178d58eSHerve Codina return ret; 3683178d58eSHerve Codina } 3693178d58eSHerve Codina EXPORT_SYMBOL(qmc_chan_write_submit); 3703178d58eSHerve Codina 3713178d58eSHerve Codina static void qmc_chan_write_done(struct qmc_chan *chan) 3723178d58eSHerve Codina { 3733178d58eSHerve Codina struct qmc_xfer_desc *xfer_desc; 3743178d58eSHerve Codina void (*complete)(void *context); 3753178d58eSHerve Codina unsigned long flags; 3763178d58eSHerve Codina void *context; 377*07d45e91SHerve Codina cbd_t __iomem *bd; 3783178d58eSHerve Codina u16 ctrl; 3793178d58eSHerve Codina 3803178d58eSHerve Codina /* 3813178d58eSHerve Codina * R bit UB bit 3823178d58eSHerve Codina * 0 0 : The BD is free 3833178d58eSHerve Codina * 1 1 : The BD is in used, waiting for transfer 3843178d58eSHerve Codina * 0 1 : The BD is in used, waiting for completion 3853178d58eSHerve Codina * 1 0 : Should not append 3863178d58eSHerve Codina */ 3873178d58eSHerve Codina 3883178d58eSHerve Codina spin_lock_irqsave(&chan->tx_lock, flags); 3893178d58eSHerve Codina bd = chan->txbd_done; 3903178d58eSHerve Codina 3913178d58eSHerve Codina ctrl = qmc_read16(&bd->cbd_sc); 3923178d58eSHerve Codina while (!(ctrl & QMC_BD_TX_R)) { 3933178d58eSHerve Codina if (!(ctrl & QMC_BD_TX_UB)) 3943178d58eSHerve Codina goto end; 3953178d58eSHerve Codina 3963178d58eSHerve Codina xfer_desc = &chan->tx_desc[bd - chan->txbds]; 3973178d58eSHerve Codina complete = xfer_desc->tx_complete; 3983178d58eSHerve Codina context = xfer_desc->context; 3993178d58eSHerve Codina xfer_desc->tx_complete = NULL; 4003178d58eSHerve Codina xfer_desc->context = NULL; 4013178d58eSHerve Codina 4023178d58eSHerve Codina qmc_write16(&bd->cbd_sc, ctrl & ~QMC_BD_TX_UB); 4033178d58eSHerve Codina 4043178d58eSHerve Codina if (ctrl & QMC_BD_TX_W) 4053178d58eSHerve Codina chan->txbd_done = chan->txbds; 4063178d58eSHerve Codina else 4073178d58eSHerve Codina chan->txbd_done++; 4083178d58eSHerve Codina 4093178d58eSHerve Codina if (complete) { 4103178d58eSHerve Codina spin_unlock_irqrestore(&chan->tx_lock, flags); 4113178d58eSHerve Codina complete(context); 4123178d58eSHerve Codina spin_lock_irqsave(&chan->tx_lock, flags); 4133178d58eSHerve Codina } 4143178d58eSHerve Codina 4153178d58eSHerve Codina bd = chan->txbd_done; 4163178d58eSHerve Codina ctrl = qmc_read16(&bd->cbd_sc); 4173178d58eSHerve Codina } 4183178d58eSHerve Codina 4193178d58eSHerve Codina end: 4203178d58eSHerve Codina spin_unlock_irqrestore(&chan->tx_lock, flags); 4213178d58eSHerve Codina } 4223178d58eSHerve Codina 4233178d58eSHerve Codina int qmc_chan_read_submit(struct qmc_chan *chan, dma_addr_t addr, size_t length, 4243178d58eSHerve Codina void (*complete)(void *context, size_t length), void *context) 4253178d58eSHerve Codina { 4263178d58eSHerve Codina struct qmc_xfer_desc *xfer_desc; 4273178d58eSHerve Codina unsigned long flags; 428*07d45e91SHerve Codina cbd_t __iomem *bd; 4293178d58eSHerve Codina u16 ctrl; 4303178d58eSHerve Codina int ret; 4313178d58eSHerve Codina 4323178d58eSHerve Codina /* 4333178d58eSHerve Codina * E bit UB bit 4343178d58eSHerve Codina * 0 0 : The BD is free 4353178d58eSHerve Codina * 1 1 : The BD is in used, waiting for transfer 4363178d58eSHerve Codina * 0 1 : The BD is in used, waiting for completion 4373178d58eSHerve Codina * 1 0 : Should not append 4383178d58eSHerve Codina */ 4393178d58eSHerve Codina 4403178d58eSHerve Codina spin_lock_irqsave(&chan->rx_lock, flags); 4413178d58eSHerve Codina bd = chan->rxbd_free; 4423178d58eSHerve Codina 4433178d58eSHerve Codina ctrl = qmc_read16(&bd->cbd_sc); 4443178d58eSHerve Codina if (ctrl & (QMC_BD_RX_E | QMC_BD_RX_UB)) { 4453178d58eSHerve Codina /* We are full ... */ 4463178d58eSHerve Codina ret = -EBUSY; 4473178d58eSHerve Codina goto end; 4483178d58eSHerve Codina } 4493178d58eSHerve Codina 4503178d58eSHerve Codina qmc_write16(&bd->cbd_datlen, 0); /* data length is updated by the QMC */ 4513178d58eSHerve Codina qmc_write32(&bd->cbd_bufaddr, addr); 4523178d58eSHerve Codina 4533178d58eSHerve Codina xfer_desc = &chan->rx_desc[bd - chan->rxbds]; 4543178d58eSHerve Codina xfer_desc->rx_complete = complete; 4553178d58eSHerve Codina xfer_desc->context = context; 4563178d58eSHerve Codina 4573178d58eSHerve Codina /* Activate the descriptor */ 4583178d58eSHerve Codina ctrl |= (QMC_BD_RX_E | QMC_BD_RX_UB); 4593178d58eSHerve Codina wmb(); /* Be sure to flush data before descriptor activation */ 4603178d58eSHerve Codina qmc_write16(&bd->cbd_sc, ctrl); 4613178d58eSHerve Codina 4623178d58eSHerve Codina /* Restart receiver if needed */ 4633178d58eSHerve Codina if (chan->is_rx_halted && !chan->is_rx_stopped) { 4643178d58eSHerve Codina /* Restart receiver */ 4653178d58eSHerve Codina if (chan->mode == QMC_TRANSPARENT) 4663178d58eSHerve Codina qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x18000080); 4673178d58eSHerve Codina else 4683178d58eSHerve Codina qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x00000080); 4693178d58eSHerve Codina qmc_write32(chan->s_param + QMC_SPE_RSTATE, 0x31000000); 4703178d58eSHerve Codina chan->is_rx_halted = false; 4713178d58eSHerve Codina } 4723178d58eSHerve Codina chan->rx_pending++; 4733178d58eSHerve Codina 4743178d58eSHerve Codina if (ctrl & QMC_BD_RX_W) 4753178d58eSHerve Codina chan->rxbd_free = chan->rxbds; 4763178d58eSHerve Codina else 4773178d58eSHerve Codina chan->rxbd_free++; 4783178d58eSHerve Codina 4793178d58eSHerve Codina ret = 0; 4803178d58eSHerve Codina end: 4813178d58eSHerve Codina spin_unlock_irqrestore(&chan->rx_lock, flags); 4823178d58eSHerve Codina return ret; 4833178d58eSHerve Codina } 4843178d58eSHerve Codina EXPORT_SYMBOL(qmc_chan_read_submit); 4853178d58eSHerve Codina 4863178d58eSHerve Codina static void qmc_chan_read_done(struct qmc_chan *chan) 4873178d58eSHerve Codina { 4883178d58eSHerve Codina void (*complete)(void *context, size_t size); 4893178d58eSHerve Codina struct qmc_xfer_desc *xfer_desc; 4903178d58eSHerve Codina unsigned long flags; 491*07d45e91SHerve Codina cbd_t __iomem *bd; 4923178d58eSHerve Codina void *context; 4933178d58eSHerve Codina u16 datalen; 4943178d58eSHerve Codina u16 ctrl; 4953178d58eSHerve Codina 4963178d58eSHerve Codina /* 4973178d58eSHerve Codina * E bit UB bit 4983178d58eSHerve Codina * 0 0 : The BD is free 4993178d58eSHerve Codina * 1 1 : The BD is in used, waiting for transfer 5003178d58eSHerve Codina * 0 1 : The BD is in used, waiting for completion 5013178d58eSHerve Codina * 1 0 : Should not append 5023178d58eSHerve Codina */ 5033178d58eSHerve Codina 5043178d58eSHerve Codina spin_lock_irqsave(&chan->rx_lock, flags); 5053178d58eSHerve Codina bd = chan->rxbd_done; 5063178d58eSHerve Codina 5073178d58eSHerve Codina ctrl = qmc_read16(&bd->cbd_sc); 5083178d58eSHerve Codina while (!(ctrl & QMC_BD_RX_E)) { 5093178d58eSHerve Codina if (!(ctrl & QMC_BD_RX_UB)) 5103178d58eSHerve Codina goto end; 5113178d58eSHerve Codina 5123178d58eSHerve Codina xfer_desc = &chan->rx_desc[bd - chan->rxbds]; 5133178d58eSHerve Codina complete = xfer_desc->rx_complete; 5143178d58eSHerve Codina context = xfer_desc->context; 5153178d58eSHerve Codina xfer_desc->rx_complete = NULL; 5163178d58eSHerve Codina xfer_desc->context = NULL; 5173178d58eSHerve Codina 5183178d58eSHerve Codina datalen = qmc_read16(&bd->cbd_datlen); 5193178d58eSHerve Codina qmc_write16(&bd->cbd_sc, ctrl & ~QMC_BD_RX_UB); 5203178d58eSHerve Codina 5213178d58eSHerve Codina if (ctrl & QMC_BD_RX_W) 5223178d58eSHerve Codina chan->rxbd_done = chan->rxbds; 5233178d58eSHerve Codina else 5243178d58eSHerve Codina chan->rxbd_done++; 5253178d58eSHerve Codina 5263178d58eSHerve Codina chan->rx_pending--; 5273178d58eSHerve Codina 5283178d58eSHerve Codina if (complete) { 5293178d58eSHerve Codina spin_unlock_irqrestore(&chan->rx_lock, flags); 5303178d58eSHerve Codina complete(context, datalen); 5313178d58eSHerve Codina spin_lock_irqsave(&chan->rx_lock, flags); 5323178d58eSHerve Codina } 5333178d58eSHerve Codina 5343178d58eSHerve Codina bd = chan->rxbd_done; 5353178d58eSHerve Codina ctrl = qmc_read16(&bd->cbd_sc); 5363178d58eSHerve Codina } 5373178d58eSHerve Codina 5383178d58eSHerve Codina end: 5393178d58eSHerve Codina spin_unlock_irqrestore(&chan->rx_lock, flags); 5403178d58eSHerve Codina } 5413178d58eSHerve Codina 5423178d58eSHerve Codina static int qmc_chan_command(struct qmc_chan *chan, u8 qmc_opcode) 5433178d58eSHerve Codina { 5443178d58eSHerve Codina return cpm_command(chan->id << 2, (qmc_opcode << 4) | 0x0E); 5453178d58eSHerve Codina } 5463178d58eSHerve Codina 5473178d58eSHerve Codina static int qmc_chan_stop_rx(struct qmc_chan *chan) 5483178d58eSHerve Codina { 5493178d58eSHerve Codina unsigned long flags; 5503178d58eSHerve Codina int ret; 5513178d58eSHerve Codina 5523178d58eSHerve Codina spin_lock_irqsave(&chan->rx_lock, flags); 5533178d58eSHerve Codina 5543178d58eSHerve Codina /* Send STOP RECEIVE command */ 5553178d58eSHerve Codina ret = qmc_chan_command(chan, 0x0); 5563178d58eSHerve Codina if (ret) { 5573178d58eSHerve Codina dev_err(chan->qmc->dev, "chan %u: Send STOP RECEIVE failed (%d)\n", 5583178d58eSHerve Codina chan->id, ret); 5593178d58eSHerve Codina goto end; 5603178d58eSHerve Codina } 5613178d58eSHerve Codina 5623178d58eSHerve Codina chan->is_rx_stopped = true; 5633178d58eSHerve Codina 5643178d58eSHerve Codina end: 5653178d58eSHerve Codina spin_unlock_irqrestore(&chan->rx_lock, flags); 5663178d58eSHerve Codina return ret; 5673178d58eSHerve Codina } 5683178d58eSHerve Codina 5693178d58eSHerve Codina static int qmc_chan_stop_tx(struct qmc_chan *chan) 5703178d58eSHerve Codina { 5713178d58eSHerve Codina unsigned long flags; 5723178d58eSHerve Codina int ret; 5733178d58eSHerve Codina 5743178d58eSHerve Codina spin_lock_irqsave(&chan->tx_lock, flags); 5753178d58eSHerve Codina 5763178d58eSHerve Codina /* Send STOP TRANSMIT command */ 5773178d58eSHerve Codina ret = qmc_chan_command(chan, 0x1); 5783178d58eSHerve Codina if (ret) { 5793178d58eSHerve Codina dev_err(chan->qmc->dev, "chan %u: Send STOP TRANSMIT failed (%d)\n", 5803178d58eSHerve Codina chan->id, ret); 5813178d58eSHerve Codina goto end; 5823178d58eSHerve Codina } 5833178d58eSHerve Codina 5843178d58eSHerve Codina chan->is_tx_stopped = true; 5853178d58eSHerve Codina 5863178d58eSHerve Codina end: 5873178d58eSHerve Codina spin_unlock_irqrestore(&chan->tx_lock, flags); 5883178d58eSHerve Codina return ret; 5893178d58eSHerve Codina } 5903178d58eSHerve Codina 5913178d58eSHerve Codina int qmc_chan_stop(struct qmc_chan *chan, int direction) 5923178d58eSHerve Codina { 5933178d58eSHerve Codina int ret; 5943178d58eSHerve Codina 5953178d58eSHerve Codina if (direction & QMC_CHAN_READ) { 5963178d58eSHerve Codina ret = qmc_chan_stop_rx(chan); 5973178d58eSHerve Codina if (ret) 5983178d58eSHerve Codina return ret; 5993178d58eSHerve Codina } 6003178d58eSHerve Codina 6013178d58eSHerve Codina if (direction & QMC_CHAN_WRITE) { 6023178d58eSHerve Codina ret = qmc_chan_stop_tx(chan); 6033178d58eSHerve Codina if (ret) 6043178d58eSHerve Codina return ret; 6053178d58eSHerve Codina } 6063178d58eSHerve Codina 6073178d58eSHerve Codina return 0; 6083178d58eSHerve Codina } 6093178d58eSHerve Codina EXPORT_SYMBOL(qmc_chan_stop); 6103178d58eSHerve Codina 6113178d58eSHerve Codina static void qmc_chan_start_rx(struct qmc_chan *chan) 6123178d58eSHerve Codina { 6133178d58eSHerve Codina unsigned long flags; 6143178d58eSHerve Codina 6153178d58eSHerve Codina spin_lock_irqsave(&chan->rx_lock, flags); 6163178d58eSHerve Codina 6173178d58eSHerve Codina /* Restart the receiver */ 6183178d58eSHerve Codina if (chan->mode == QMC_TRANSPARENT) 6193178d58eSHerve Codina qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x18000080); 6203178d58eSHerve Codina else 6213178d58eSHerve Codina qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x00000080); 6223178d58eSHerve Codina qmc_write32(chan->s_param + QMC_SPE_RSTATE, 0x31000000); 6233178d58eSHerve Codina chan->is_rx_halted = false; 6243178d58eSHerve Codina 6253178d58eSHerve Codina chan->is_rx_stopped = false; 6263178d58eSHerve Codina 6273178d58eSHerve Codina spin_unlock_irqrestore(&chan->rx_lock, flags); 6283178d58eSHerve Codina } 6293178d58eSHerve Codina 6303178d58eSHerve Codina static void qmc_chan_start_tx(struct qmc_chan *chan) 6313178d58eSHerve Codina { 6323178d58eSHerve Codina unsigned long flags; 6333178d58eSHerve Codina 6343178d58eSHerve Codina spin_lock_irqsave(&chan->tx_lock, flags); 6353178d58eSHerve Codina 6363178d58eSHerve Codina /* 6373178d58eSHerve Codina * Enable channel transmitter as it could be disabled if 6383178d58eSHerve Codina * qmc_chan_reset() was called. 6393178d58eSHerve Codina */ 6403178d58eSHerve Codina qmc_setbits16(chan->s_param + QMC_SPE_CHAMR, QMC_SPE_CHAMR_ENT); 6413178d58eSHerve Codina 6423178d58eSHerve Codina /* Set the POL bit in the channel mode register */ 6433178d58eSHerve Codina qmc_setbits16(chan->s_param + QMC_SPE_CHAMR, QMC_SPE_CHAMR_POL); 6443178d58eSHerve Codina 6453178d58eSHerve Codina chan->is_tx_stopped = false; 6463178d58eSHerve Codina 6473178d58eSHerve Codina spin_unlock_irqrestore(&chan->tx_lock, flags); 6483178d58eSHerve Codina } 6493178d58eSHerve Codina 6503178d58eSHerve Codina int qmc_chan_start(struct qmc_chan *chan, int direction) 6513178d58eSHerve Codina { 6523178d58eSHerve Codina if (direction & QMC_CHAN_READ) 6533178d58eSHerve Codina qmc_chan_start_rx(chan); 6543178d58eSHerve Codina 6553178d58eSHerve Codina if (direction & QMC_CHAN_WRITE) 6563178d58eSHerve Codina qmc_chan_start_tx(chan); 6573178d58eSHerve Codina 6583178d58eSHerve Codina return 0; 6593178d58eSHerve Codina } 6603178d58eSHerve Codina EXPORT_SYMBOL(qmc_chan_start); 6613178d58eSHerve Codina 6623178d58eSHerve Codina static void qmc_chan_reset_rx(struct qmc_chan *chan) 6633178d58eSHerve Codina { 6643178d58eSHerve Codina struct qmc_xfer_desc *xfer_desc; 6653178d58eSHerve Codina unsigned long flags; 666*07d45e91SHerve Codina cbd_t __iomem *bd; 6673178d58eSHerve Codina u16 ctrl; 6683178d58eSHerve Codina 6693178d58eSHerve Codina spin_lock_irqsave(&chan->rx_lock, flags); 6703178d58eSHerve Codina bd = chan->rxbds; 6713178d58eSHerve Codina do { 6723178d58eSHerve Codina ctrl = qmc_read16(&bd->cbd_sc); 6733178d58eSHerve Codina qmc_write16(&bd->cbd_sc, ctrl & ~(QMC_BD_RX_UB | QMC_BD_RX_E)); 6743178d58eSHerve Codina 6753178d58eSHerve Codina xfer_desc = &chan->rx_desc[bd - chan->rxbds]; 6763178d58eSHerve Codina xfer_desc->rx_complete = NULL; 6773178d58eSHerve Codina xfer_desc->context = NULL; 6783178d58eSHerve Codina 6793178d58eSHerve Codina bd++; 6803178d58eSHerve Codina } while (!(ctrl & QMC_BD_RX_W)); 6813178d58eSHerve Codina 6823178d58eSHerve Codina chan->rxbd_free = chan->rxbds; 6833178d58eSHerve Codina chan->rxbd_done = chan->rxbds; 6843178d58eSHerve Codina qmc_write16(chan->s_param + QMC_SPE_RBPTR, 6853178d58eSHerve Codina qmc_read16(chan->s_param + QMC_SPE_RBASE)); 6863178d58eSHerve Codina 6873178d58eSHerve Codina chan->rx_pending = 0; 6883178d58eSHerve Codina chan->is_rx_stopped = false; 6893178d58eSHerve Codina 6903178d58eSHerve Codina spin_unlock_irqrestore(&chan->rx_lock, flags); 6913178d58eSHerve Codina } 6923178d58eSHerve Codina 6933178d58eSHerve Codina static void qmc_chan_reset_tx(struct qmc_chan *chan) 6943178d58eSHerve Codina { 6953178d58eSHerve Codina struct qmc_xfer_desc *xfer_desc; 6963178d58eSHerve Codina unsigned long flags; 697*07d45e91SHerve Codina cbd_t __iomem *bd; 6983178d58eSHerve Codina u16 ctrl; 6993178d58eSHerve Codina 7003178d58eSHerve Codina spin_lock_irqsave(&chan->tx_lock, flags); 7013178d58eSHerve Codina 7023178d58eSHerve Codina /* Disable transmitter. It will be re-enable on qmc_chan_start() */ 7033178d58eSHerve Codina qmc_clrbits16(chan->s_param + QMC_SPE_CHAMR, QMC_SPE_CHAMR_ENT); 7043178d58eSHerve Codina 7053178d58eSHerve Codina bd = chan->txbds; 7063178d58eSHerve Codina do { 7073178d58eSHerve Codina ctrl = qmc_read16(&bd->cbd_sc); 7083178d58eSHerve Codina qmc_write16(&bd->cbd_sc, ctrl & ~(QMC_BD_TX_UB | QMC_BD_TX_R)); 7093178d58eSHerve Codina 7103178d58eSHerve Codina xfer_desc = &chan->tx_desc[bd - chan->txbds]; 7113178d58eSHerve Codina xfer_desc->tx_complete = NULL; 7123178d58eSHerve Codina xfer_desc->context = NULL; 7133178d58eSHerve Codina 7143178d58eSHerve Codina bd++; 7153178d58eSHerve Codina } while (!(ctrl & QMC_BD_TX_W)); 7163178d58eSHerve Codina 7173178d58eSHerve Codina chan->txbd_free = chan->txbds; 7183178d58eSHerve Codina chan->txbd_done = chan->txbds; 7193178d58eSHerve Codina qmc_write16(chan->s_param + QMC_SPE_TBPTR, 7203178d58eSHerve Codina qmc_read16(chan->s_param + QMC_SPE_TBASE)); 7213178d58eSHerve Codina 7223178d58eSHerve Codina /* Reset TSTATE and ZISTATE to their initial value */ 7233178d58eSHerve Codina qmc_write32(chan->s_param + QMC_SPE_TSTATE, 0x30000000); 7243178d58eSHerve Codina qmc_write32(chan->s_param + QMC_SPE_ZISTATE, 0x00000100); 7253178d58eSHerve Codina 7263178d58eSHerve Codina spin_unlock_irqrestore(&chan->tx_lock, flags); 7273178d58eSHerve Codina } 7283178d58eSHerve Codina 7293178d58eSHerve Codina int qmc_chan_reset(struct qmc_chan *chan, int direction) 7303178d58eSHerve Codina { 7313178d58eSHerve Codina if (direction & QMC_CHAN_READ) 7323178d58eSHerve Codina qmc_chan_reset_rx(chan); 7333178d58eSHerve Codina 7343178d58eSHerve Codina if (direction & QMC_CHAN_WRITE) 7353178d58eSHerve Codina qmc_chan_reset_tx(chan); 7363178d58eSHerve Codina 7373178d58eSHerve Codina return 0; 7383178d58eSHerve Codina } 7393178d58eSHerve Codina EXPORT_SYMBOL(qmc_chan_reset); 7403178d58eSHerve Codina 7413178d58eSHerve Codina static int qmc_check_chans(struct qmc *qmc) 7423178d58eSHerve Codina { 7433178d58eSHerve Codina struct tsa_serial_info info; 7443178d58eSHerve Codina bool is_one_table = false; 7453178d58eSHerve Codina struct qmc_chan *chan; 7463178d58eSHerve Codina u64 tx_ts_mask = 0; 7473178d58eSHerve Codina u64 rx_ts_mask = 0; 7483178d58eSHerve Codina u64 tx_ts_assigned_mask; 7493178d58eSHerve Codina u64 rx_ts_assigned_mask; 7503178d58eSHerve Codina int ret; 7513178d58eSHerve Codina 7523178d58eSHerve Codina /* Retrieve info from the TSA related serial */ 7533178d58eSHerve Codina ret = tsa_serial_get_info(qmc->tsa_serial, &info); 7543178d58eSHerve Codina if (ret) 7553178d58eSHerve Codina return ret; 7563178d58eSHerve Codina 757f37acbdeSHerve Codina via Alsa-devel if ((info.nb_tx_ts > 64) || (info.nb_rx_ts > 64)) { 758f37acbdeSHerve Codina via Alsa-devel dev_err(qmc->dev, "Number of TSA Tx/Rx TS assigned not supported\n"); 759f37acbdeSHerve Codina via Alsa-devel return -EINVAL; 760f37acbdeSHerve Codina via Alsa-devel } 761f37acbdeSHerve Codina via Alsa-devel 7623178d58eSHerve Codina /* 7633178d58eSHerve Codina * If more than 32 TS are assigned to this serial, one common table is 7643178d58eSHerve Codina * used for Tx and Rx and so masks must be equal for all channels. 7653178d58eSHerve Codina */ 7663178d58eSHerve Codina if ((info.nb_tx_ts > 32) || (info.nb_rx_ts > 32)) { 7673178d58eSHerve Codina if (info.nb_tx_ts != info.nb_rx_ts) { 7683178d58eSHerve Codina dev_err(qmc->dev, "Number of TSA Tx/Rx TS assigned are not equal\n"); 7693178d58eSHerve Codina return -EINVAL; 7703178d58eSHerve Codina } 7713178d58eSHerve Codina is_one_table = true; 7723178d58eSHerve Codina } 7733178d58eSHerve Codina 774f37acbdeSHerve Codina via Alsa-devel tx_ts_assigned_mask = info.nb_tx_ts == 64 ? U64_MAX : (((u64)1) << info.nb_tx_ts) - 1; 775f37acbdeSHerve Codina via Alsa-devel rx_ts_assigned_mask = info.nb_rx_ts == 64 ? U64_MAX : (((u64)1) << info.nb_rx_ts) - 1; 7763178d58eSHerve Codina 7773178d58eSHerve Codina list_for_each_entry(chan, &qmc->chan_head, list) { 7783178d58eSHerve Codina if (chan->tx_ts_mask > tx_ts_assigned_mask) { 7793178d58eSHerve Codina dev_err(qmc->dev, "chan %u uses TSA unassigned Tx TS\n", chan->id); 7803178d58eSHerve Codina return -EINVAL; 7813178d58eSHerve Codina } 7823178d58eSHerve Codina if (tx_ts_mask & chan->tx_ts_mask) { 7833178d58eSHerve Codina dev_err(qmc->dev, "chan %u uses an already used Tx TS\n", chan->id); 7843178d58eSHerve Codina return -EINVAL; 7853178d58eSHerve Codina } 7863178d58eSHerve Codina 7873178d58eSHerve Codina if (chan->rx_ts_mask > rx_ts_assigned_mask) { 7883178d58eSHerve Codina dev_err(qmc->dev, "chan %u uses TSA unassigned Rx TS\n", chan->id); 7893178d58eSHerve Codina return -EINVAL; 7903178d58eSHerve Codina } 7913178d58eSHerve Codina if (rx_ts_mask & chan->rx_ts_mask) { 7923178d58eSHerve Codina dev_err(qmc->dev, "chan %u uses an already used Rx TS\n", chan->id); 7933178d58eSHerve Codina return -EINVAL; 7943178d58eSHerve Codina } 7953178d58eSHerve Codina 7963178d58eSHerve Codina if (is_one_table && (chan->tx_ts_mask != chan->rx_ts_mask)) { 7973178d58eSHerve Codina dev_err(qmc->dev, "chan %u uses different Rx and Tx TS\n", chan->id); 7983178d58eSHerve Codina return -EINVAL; 7993178d58eSHerve Codina } 8003178d58eSHerve Codina 8013178d58eSHerve Codina tx_ts_mask |= chan->tx_ts_mask; 8023178d58eSHerve Codina rx_ts_mask |= chan->rx_ts_mask; 8033178d58eSHerve Codina } 8043178d58eSHerve Codina 8053178d58eSHerve Codina return 0; 8063178d58eSHerve Codina } 8073178d58eSHerve Codina 8083178d58eSHerve Codina static unsigned int qmc_nb_chans(struct qmc *qmc) 8093178d58eSHerve Codina { 8103178d58eSHerve Codina unsigned int count = 0; 8113178d58eSHerve Codina struct qmc_chan *chan; 8123178d58eSHerve Codina 8133178d58eSHerve Codina list_for_each_entry(chan, &qmc->chan_head, list) 8143178d58eSHerve Codina count++; 8153178d58eSHerve Codina 8163178d58eSHerve Codina return count; 8173178d58eSHerve Codina } 8183178d58eSHerve Codina 8193178d58eSHerve Codina static int qmc_of_parse_chans(struct qmc *qmc, struct device_node *np) 8203178d58eSHerve Codina { 8213178d58eSHerve Codina struct device_node *chan_np; 8223178d58eSHerve Codina struct qmc_chan *chan; 8233178d58eSHerve Codina const char *mode; 8243178d58eSHerve Codina u32 chan_id; 8253178d58eSHerve Codina u64 ts_mask; 8263178d58eSHerve Codina int ret; 8273178d58eSHerve Codina 8283178d58eSHerve Codina for_each_available_child_of_node(np, chan_np) { 8293178d58eSHerve Codina ret = of_property_read_u32(chan_np, "reg", &chan_id); 8303178d58eSHerve Codina if (ret) { 8313178d58eSHerve Codina dev_err(qmc->dev, "%pOF: failed to read reg\n", chan_np); 8323178d58eSHerve Codina of_node_put(chan_np); 8333178d58eSHerve Codina return ret; 8343178d58eSHerve Codina } 8353178d58eSHerve Codina if (chan_id > 63) { 8363178d58eSHerve Codina dev_err(qmc->dev, "%pOF: Invalid chan_id\n", chan_np); 8373178d58eSHerve Codina of_node_put(chan_np); 8383178d58eSHerve Codina return -EINVAL; 8393178d58eSHerve Codina } 8403178d58eSHerve Codina 8413178d58eSHerve Codina chan = devm_kzalloc(qmc->dev, sizeof(*chan), GFP_KERNEL); 8423178d58eSHerve Codina if (!chan) { 8433178d58eSHerve Codina of_node_put(chan_np); 8443178d58eSHerve Codina return -ENOMEM; 8453178d58eSHerve Codina } 8463178d58eSHerve Codina 8473178d58eSHerve Codina chan->id = chan_id; 8483178d58eSHerve Codina spin_lock_init(&chan->rx_lock); 8493178d58eSHerve Codina spin_lock_init(&chan->tx_lock); 8503178d58eSHerve Codina 8513178d58eSHerve Codina ret = of_property_read_u64(chan_np, "fsl,tx-ts-mask", &ts_mask); 8523178d58eSHerve Codina if (ret) { 8533178d58eSHerve Codina dev_err(qmc->dev, "%pOF: failed to read fsl,tx-ts-mask\n", 8543178d58eSHerve Codina chan_np); 8553178d58eSHerve Codina of_node_put(chan_np); 8563178d58eSHerve Codina return ret; 8573178d58eSHerve Codina } 8583178d58eSHerve Codina chan->tx_ts_mask = ts_mask; 8593178d58eSHerve Codina 8603178d58eSHerve Codina ret = of_property_read_u64(chan_np, "fsl,rx-ts-mask", &ts_mask); 8613178d58eSHerve Codina if (ret) { 8623178d58eSHerve Codina dev_err(qmc->dev, "%pOF: failed to read fsl,rx-ts-mask\n", 8633178d58eSHerve Codina chan_np); 8643178d58eSHerve Codina of_node_put(chan_np); 8653178d58eSHerve Codina return ret; 8663178d58eSHerve Codina } 8673178d58eSHerve Codina chan->rx_ts_mask = ts_mask; 8683178d58eSHerve Codina 8693178d58eSHerve Codina mode = "transparent"; 8703178d58eSHerve Codina ret = of_property_read_string(chan_np, "fsl,operational-mode", &mode); 8713178d58eSHerve Codina if (ret && ret != -EINVAL) { 8723178d58eSHerve Codina dev_err(qmc->dev, "%pOF: failed to read fsl,operational-mode\n", 8733178d58eSHerve Codina chan_np); 8743178d58eSHerve Codina of_node_put(chan_np); 8753178d58eSHerve Codina return ret; 8763178d58eSHerve Codina } 8773178d58eSHerve Codina if (!strcmp(mode, "transparent")) { 8783178d58eSHerve Codina chan->mode = QMC_TRANSPARENT; 8793178d58eSHerve Codina } else if (!strcmp(mode, "hdlc")) { 8803178d58eSHerve Codina chan->mode = QMC_HDLC; 8813178d58eSHerve Codina } else { 8823178d58eSHerve Codina dev_err(qmc->dev, "%pOF: Invalid fsl,operational-mode (%s)\n", 8833178d58eSHerve Codina chan_np, mode); 8843178d58eSHerve Codina of_node_put(chan_np); 8853178d58eSHerve Codina return -EINVAL; 8863178d58eSHerve Codina } 8873178d58eSHerve Codina 8883178d58eSHerve Codina chan->is_reverse_data = of_property_read_bool(chan_np, 8893178d58eSHerve Codina "fsl,reverse-data"); 8903178d58eSHerve Codina 8913178d58eSHerve Codina list_add_tail(&chan->list, &qmc->chan_head); 8923178d58eSHerve Codina qmc->chans[chan->id] = chan; 8933178d58eSHerve Codina } 8943178d58eSHerve Codina 8953178d58eSHerve Codina return qmc_check_chans(qmc); 8963178d58eSHerve Codina } 8973178d58eSHerve Codina 8983178d58eSHerve Codina static int qmc_setup_tsa_64rxtx(struct qmc *qmc, const struct tsa_serial_info *info) 8993178d58eSHerve Codina { 9003178d58eSHerve Codina struct qmc_chan *chan; 9013178d58eSHerve Codina unsigned int i; 9023178d58eSHerve Codina u16 val; 9033178d58eSHerve Codina 9043178d58eSHerve Codina /* 9053178d58eSHerve Codina * Use a common Tx/Rx 64 entries table. 9063178d58eSHerve Codina * Everything was previously checked, Tx and Rx related stuffs are 9073178d58eSHerve Codina * identical -> Used Rx related stuff to build the table 9083178d58eSHerve Codina */ 9093178d58eSHerve Codina 9103178d58eSHerve Codina /* Invalidate all entries */ 9113178d58eSHerve Codina for (i = 0; i < 64; i++) 9123178d58eSHerve Codina qmc_write16(qmc->scc_pram + QMC_GBL_TSATRX + (i * 2), 0x0000); 9133178d58eSHerve Codina 9143178d58eSHerve Codina /* Set entries based on Rx stuff*/ 9153178d58eSHerve Codina list_for_each_entry(chan, &qmc->chan_head, list) { 9163178d58eSHerve Codina for (i = 0; i < info->nb_rx_ts; i++) { 9173178d58eSHerve Codina if (!(chan->rx_ts_mask & (((u64)1) << i))) 9183178d58eSHerve Codina continue; 9193178d58eSHerve Codina 9203178d58eSHerve Codina val = QMC_TSA_VALID | QMC_TSA_MASK | 9213178d58eSHerve Codina QMC_TSA_CHANNEL(chan->id); 9223178d58eSHerve Codina qmc_write16(qmc->scc_pram + QMC_GBL_TSATRX + (i * 2), val); 9233178d58eSHerve Codina } 9243178d58eSHerve Codina } 9253178d58eSHerve Codina 9263178d58eSHerve Codina /* Set Wrap bit on last entry */ 9273178d58eSHerve Codina qmc_setbits16(qmc->scc_pram + QMC_GBL_TSATRX + ((info->nb_rx_ts - 1) * 2), 9283178d58eSHerve Codina QMC_TSA_WRAP); 9293178d58eSHerve Codina 9303178d58eSHerve Codina /* Init pointers to the table */ 9313178d58eSHerve Codina val = qmc->scc_pram_offset + QMC_GBL_TSATRX; 9323178d58eSHerve Codina qmc_write16(qmc->scc_pram + QMC_GBL_RX_S_PTR, val); 9333178d58eSHerve Codina qmc_write16(qmc->scc_pram + QMC_GBL_RXPTR, val); 9343178d58eSHerve Codina qmc_write16(qmc->scc_pram + QMC_GBL_TX_S_PTR, val); 9353178d58eSHerve Codina qmc_write16(qmc->scc_pram + QMC_GBL_TXPTR, val); 9363178d58eSHerve Codina 9373178d58eSHerve Codina return 0; 9383178d58eSHerve Codina } 9393178d58eSHerve Codina 9403178d58eSHerve Codina static int qmc_setup_tsa_32rx_32tx(struct qmc *qmc, const struct tsa_serial_info *info) 9413178d58eSHerve Codina { 9423178d58eSHerve Codina struct qmc_chan *chan; 9433178d58eSHerve Codina unsigned int i; 9443178d58eSHerve Codina u16 val; 9453178d58eSHerve Codina 9463178d58eSHerve Codina /* 9473178d58eSHerve Codina * Use a Tx 32 entries table and a Rx 32 entries table. 9483178d58eSHerve Codina * Everything was previously checked. 9493178d58eSHerve Codina */ 9503178d58eSHerve Codina 9513178d58eSHerve Codina /* Invalidate all entries */ 9523178d58eSHerve Codina for (i = 0; i < 32; i++) { 9533178d58eSHerve Codina qmc_write16(qmc->scc_pram + QMC_GBL_TSATRX + (i * 2), 0x0000); 9543178d58eSHerve Codina qmc_write16(qmc->scc_pram + QMC_GBL_TSATTX + (i * 2), 0x0000); 9553178d58eSHerve Codina } 9563178d58eSHerve Codina 9573178d58eSHerve Codina /* Set entries based on Rx and Tx stuff*/ 9583178d58eSHerve Codina list_for_each_entry(chan, &qmc->chan_head, list) { 9593178d58eSHerve Codina /* Rx part */ 9603178d58eSHerve Codina for (i = 0; i < info->nb_rx_ts; i++) { 9613178d58eSHerve Codina if (!(chan->rx_ts_mask & (((u64)1) << i))) 9623178d58eSHerve Codina continue; 9633178d58eSHerve Codina 9643178d58eSHerve Codina val = QMC_TSA_VALID | QMC_TSA_MASK | 9653178d58eSHerve Codina QMC_TSA_CHANNEL(chan->id); 9663178d58eSHerve Codina qmc_write16(qmc->scc_pram + QMC_GBL_TSATRX + (i * 2), val); 9673178d58eSHerve Codina } 9683178d58eSHerve Codina /* Tx part */ 9693178d58eSHerve Codina for (i = 0; i < info->nb_tx_ts; i++) { 9703178d58eSHerve Codina if (!(chan->tx_ts_mask & (((u64)1) << i))) 9713178d58eSHerve Codina continue; 9723178d58eSHerve Codina 9733178d58eSHerve Codina val = QMC_TSA_VALID | QMC_TSA_MASK | 9743178d58eSHerve Codina QMC_TSA_CHANNEL(chan->id); 9753178d58eSHerve Codina qmc_write16(qmc->scc_pram + QMC_GBL_TSATTX + (i * 2), val); 9763178d58eSHerve Codina } 9773178d58eSHerve Codina } 9783178d58eSHerve Codina 9793178d58eSHerve Codina /* Set Wrap bit on last entries */ 9803178d58eSHerve Codina qmc_setbits16(qmc->scc_pram + QMC_GBL_TSATRX + ((info->nb_rx_ts - 1) * 2), 9813178d58eSHerve Codina QMC_TSA_WRAP); 9823178d58eSHerve Codina qmc_setbits16(qmc->scc_pram + QMC_GBL_TSATTX + ((info->nb_tx_ts - 1) * 2), 9833178d58eSHerve Codina QMC_TSA_WRAP); 9843178d58eSHerve Codina 9853178d58eSHerve Codina /* Init Rx pointers ...*/ 9863178d58eSHerve Codina val = qmc->scc_pram_offset + QMC_GBL_TSATRX; 9873178d58eSHerve Codina qmc_write16(qmc->scc_pram + QMC_GBL_RX_S_PTR, val); 9883178d58eSHerve Codina qmc_write16(qmc->scc_pram + QMC_GBL_RXPTR, val); 9893178d58eSHerve Codina 9903178d58eSHerve Codina /* ... and Tx pointers */ 9913178d58eSHerve Codina val = qmc->scc_pram_offset + QMC_GBL_TSATTX; 9923178d58eSHerve Codina qmc_write16(qmc->scc_pram + QMC_GBL_TX_S_PTR, val); 9933178d58eSHerve Codina qmc_write16(qmc->scc_pram + QMC_GBL_TXPTR, val); 9943178d58eSHerve Codina 9953178d58eSHerve Codina return 0; 9963178d58eSHerve Codina } 9973178d58eSHerve Codina 9983178d58eSHerve Codina static int qmc_setup_tsa(struct qmc *qmc) 9993178d58eSHerve Codina { 10003178d58eSHerve Codina struct tsa_serial_info info; 10013178d58eSHerve Codina int ret; 10023178d58eSHerve Codina 10033178d58eSHerve Codina /* Retrieve info from the TSA related serial */ 10043178d58eSHerve Codina ret = tsa_serial_get_info(qmc->tsa_serial, &info); 10053178d58eSHerve Codina if (ret) 10063178d58eSHerve Codina return ret; 10073178d58eSHerve Codina 10083178d58eSHerve Codina /* 10093178d58eSHerve Codina * Setup one common 64 entries table or two 32 entries (one for Tx and 10103178d58eSHerve Codina * one for Tx) according to assigned TS numbers. 10113178d58eSHerve Codina */ 10123178d58eSHerve Codina return ((info.nb_tx_ts > 32) || (info.nb_rx_ts > 32)) ? 10133178d58eSHerve Codina qmc_setup_tsa_64rxtx(qmc, &info) : 10143178d58eSHerve Codina qmc_setup_tsa_32rx_32tx(qmc, &info); 10153178d58eSHerve Codina } 10163178d58eSHerve Codina 10173178d58eSHerve Codina static int qmc_setup_chan_trnsync(struct qmc *qmc, struct qmc_chan *chan) 10183178d58eSHerve Codina { 10193178d58eSHerve Codina struct tsa_serial_info info; 10203178d58eSHerve Codina u16 first_rx, last_tx; 10213178d58eSHerve Codina u16 trnsync; 10223178d58eSHerve Codina int ret; 10233178d58eSHerve Codina 10243178d58eSHerve Codina /* Retrieve info from the TSA related serial */ 10253178d58eSHerve Codina ret = tsa_serial_get_info(chan->qmc->tsa_serial, &info); 10263178d58eSHerve Codina if (ret) 10273178d58eSHerve Codina return ret; 10283178d58eSHerve Codina 10293178d58eSHerve Codina /* Find the first Rx TS allocated to the channel */ 10303178d58eSHerve Codina first_rx = chan->rx_ts_mask ? __ffs64(chan->rx_ts_mask) + 1 : 0; 10313178d58eSHerve Codina 10323178d58eSHerve Codina /* Find the last Tx TS allocated to the channel */ 10333178d58eSHerve Codina last_tx = fls64(chan->tx_ts_mask); 10343178d58eSHerve Codina 10353178d58eSHerve Codina trnsync = 0; 10363178d58eSHerve Codina if (info.nb_rx_ts) 10373178d58eSHerve Codina trnsync |= QMC_SPE_TRNSYNC_RX((first_rx % info.nb_rx_ts) * 2); 10383178d58eSHerve Codina if (info.nb_tx_ts) 10393178d58eSHerve Codina trnsync |= QMC_SPE_TRNSYNC_TX((last_tx % info.nb_tx_ts) * 2); 10403178d58eSHerve Codina 10413178d58eSHerve Codina qmc_write16(chan->s_param + QMC_SPE_TRNSYNC, trnsync); 10423178d58eSHerve Codina 10433178d58eSHerve Codina dev_dbg(qmc->dev, "chan %u: trnsync=0x%04x, rx %u/%u 0x%llx, tx %u/%u 0x%llx\n", 10443178d58eSHerve Codina chan->id, trnsync, 10453178d58eSHerve Codina first_rx, info.nb_rx_ts, chan->rx_ts_mask, 10463178d58eSHerve Codina last_tx, info.nb_tx_ts, chan->tx_ts_mask); 10473178d58eSHerve Codina 10483178d58eSHerve Codina return 0; 10493178d58eSHerve Codina } 10503178d58eSHerve Codina 10513178d58eSHerve Codina static int qmc_setup_chan(struct qmc *qmc, struct qmc_chan *chan) 10523178d58eSHerve Codina { 10533178d58eSHerve Codina unsigned int i; 10543178d58eSHerve Codina cbd_t __iomem *bd; 10553178d58eSHerve Codina int ret; 10563178d58eSHerve Codina u16 val; 10573178d58eSHerve Codina 10583178d58eSHerve Codina chan->qmc = qmc; 10593178d58eSHerve Codina 10603178d58eSHerve Codina /* Set channel specific parameter base address */ 10613178d58eSHerve Codina chan->s_param = qmc->dpram + (chan->id * 64); 10623178d58eSHerve Codina /* 16 bd per channel (8 rx and 8 tx) */ 10633178d58eSHerve Codina chan->txbds = qmc->bd_table + (chan->id * (QMC_NB_TXBDS + QMC_NB_RXBDS)); 10643178d58eSHerve Codina chan->rxbds = qmc->bd_table + (chan->id * (QMC_NB_TXBDS + QMC_NB_RXBDS)) + QMC_NB_TXBDS; 10653178d58eSHerve Codina 10663178d58eSHerve Codina chan->txbd_free = chan->txbds; 10673178d58eSHerve Codina chan->txbd_done = chan->txbds; 10683178d58eSHerve Codina chan->rxbd_free = chan->rxbds; 10693178d58eSHerve Codina chan->rxbd_done = chan->rxbds; 10703178d58eSHerve Codina 10713178d58eSHerve Codina /* TBASE and TBPTR*/ 10723178d58eSHerve Codina val = chan->id * (QMC_NB_TXBDS + QMC_NB_RXBDS) * sizeof(cbd_t); 10733178d58eSHerve Codina qmc_write16(chan->s_param + QMC_SPE_TBASE, val); 10743178d58eSHerve Codina qmc_write16(chan->s_param + QMC_SPE_TBPTR, val); 10753178d58eSHerve Codina 10763178d58eSHerve Codina /* RBASE and RBPTR*/ 10773178d58eSHerve Codina val = ((chan->id * (QMC_NB_TXBDS + QMC_NB_RXBDS)) + QMC_NB_TXBDS) * sizeof(cbd_t); 10783178d58eSHerve Codina qmc_write16(chan->s_param + QMC_SPE_RBASE, val); 10793178d58eSHerve Codina qmc_write16(chan->s_param + QMC_SPE_RBPTR, val); 10803178d58eSHerve Codina qmc_write32(chan->s_param + QMC_SPE_TSTATE, 0x30000000); 10813178d58eSHerve Codina qmc_write32(chan->s_param + QMC_SPE_RSTATE, 0x31000000); 10823178d58eSHerve Codina qmc_write32(chan->s_param + QMC_SPE_ZISTATE, 0x00000100); 10833178d58eSHerve Codina if (chan->mode == QMC_TRANSPARENT) { 10843178d58eSHerve Codina qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x18000080); 10853178d58eSHerve Codina qmc_write16(chan->s_param + QMC_SPE_TMRBLR, 60); 10863178d58eSHerve Codina val = QMC_SPE_CHAMR_MODE_TRANSP | QMC_SPE_CHAMR_TRANSP_SYNC; 10873178d58eSHerve Codina if (chan->is_reverse_data) 10883178d58eSHerve Codina val |= QMC_SPE_CHAMR_TRANSP_RD; 10893178d58eSHerve Codina qmc_write16(chan->s_param + QMC_SPE_CHAMR, val); 10903178d58eSHerve Codina ret = qmc_setup_chan_trnsync(qmc, chan); 10913178d58eSHerve Codina if (ret) 10923178d58eSHerve Codina return ret; 10933178d58eSHerve Codina } else { 10943178d58eSHerve Codina qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x00000080); 10953178d58eSHerve Codina qmc_write16(chan->s_param + QMC_SPE_MFLR, 60); 10963178d58eSHerve Codina qmc_write16(chan->s_param + QMC_SPE_CHAMR, 10973178d58eSHerve Codina QMC_SPE_CHAMR_MODE_HDLC | QMC_SPE_CHAMR_HDLC_IDLM); 10983178d58eSHerve Codina } 10993178d58eSHerve Codina 11003178d58eSHerve Codina /* Do not enable interrupts now. They will be enabled later */ 11013178d58eSHerve Codina qmc_write16(chan->s_param + QMC_SPE_INTMSK, 0x0000); 11023178d58eSHerve Codina 11033178d58eSHerve Codina /* Init Rx BDs and set Wrap bit on last descriptor */ 11043178d58eSHerve Codina BUILD_BUG_ON(QMC_NB_RXBDS == 0); 11053178d58eSHerve Codina val = QMC_BD_RX_I; 11063178d58eSHerve Codina for (i = 0; i < QMC_NB_RXBDS; i++) { 11073178d58eSHerve Codina bd = chan->rxbds + i; 11083178d58eSHerve Codina qmc_write16(&bd->cbd_sc, val); 11093178d58eSHerve Codina } 11103178d58eSHerve Codina bd = chan->rxbds + QMC_NB_RXBDS - 1; 11113178d58eSHerve Codina qmc_write16(&bd->cbd_sc, val | QMC_BD_RX_W); 11123178d58eSHerve Codina 11133178d58eSHerve Codina /* Init Tx BDs and set Wrap bit on last descriptor */ 11143178d58eSHerve Codina BUILD_BUG_ON(QMC_NB_TXBDS == 0); 11153178d58eSHerve Codina val = QMC_BD_TX_I; 11163178d58eSHerve Codina if (chan->mode == QMC_HDLC) 11173178d58eSHerve Codina val |= QMC_BD_TX_L | QMC_BD_TX_TC; 11183178d58eSHerve Codina for (i = 0; i < QMC_NB_TXBDS; i++) { 11193178d58eSHerve Codina bd = chan->txbds + i; 11203178d58eSHerve Codina qmc_write16(&bd->cbd_sc, val); 11213178d58eSHerve Codina } 11223178d58eSHerve Codina bd = chan->txbds + QMC_NB_TXBDS - 1; 11233178d58eSHerve Codina qmc_write16(&bd->cbd_sc, val | QMC_BD_TX_W); 11243178d58eSHerve Codina 11253178d58eSHerve Codina return 0; 11263178d58eSHerve Codina } 11273178d58eSHerve Codina 11283178d58eSHerve Codina static int qmc_setup_chans(struct qmc *qmc) 11293178d58eSHerve Codina { 11303178d58eSHerve Codina struct qmc_chan *chan; 11313178d58eSHerve Codina int ret; 11323178d58eSHerve Codina 11333178d58eSHerve Codina list_for_each_entry(chan, &qmc->chan_head, list) { 11343178d58eSHerve Codina ret = qmc_setup_chan(qmc, chan); 11353178d58eSHerve Codina if (ret) 11363178d58eSHerve Codina return ret; 11373178d58eSHerve Codina } 11383178d58eSHerve Codina 11393178d58eSHerve Codina return 0; 11403178d58eSHerve Codina } 11413178d58eSHerve Codina 11423178d58eSHerve Codina static int qmc_finalize_chans(struct qmc *qmc) 11433178d58eSHerve Codina { 11443178d58eSHerve Codina struct qmc_chan *chan; 11453178d58eSHerve Codina int ret; 11463178d58eSHerve Codina 11473178d58eSHerve Codina list_for_each_entry(chan, &qmc->chan_head, list) { 11483178d58eSHerve Codina /* Unmask channel interrupts */ 11493178d58eSHerve Codina if (chan->mode == QMC_HDLC) { 11503178d58eSHerve Codina qmc_write16(chan->s_param + QMC_SPE_INTMSK, 11513178d58eSHerve Codina QMC_INT_NID | QMC_INT_IDL | QMC_INT_MRF | 11523178d58eSHerve Codina QMC_INT_UN | QMC_INT_RXF | QMC_INT_BSY | 11533178d58eSHerve Codina QMC_INT_TXB | QMC_INT_RXB); 11543178d58eSHerve Codina } else { 11553178d58eSHerve Codina qmc_write16(chan->s_param + QMC_SPE_INTMSK, 11563178d58eSHerve Codina QMC_INT_UN | QMC_INT_BSY | 11573178d58eSHerve Codina QMC_INT_TXB | QMC_INT_RXB); 11583178d58eSHerve Codina } 11593178d58eSHerve Codina 11603178d58eSHerve Codina /* Forced stop the channel */ 11613178d58eSHerve Codina ret = qmc_chan_stop(chan, QMC_CHAN_ALL); 11623178d58eSHerve Codina if (ret) 11633178d58eSHerve Codina return ret; 11643178d58eSHerve Codina } 11653178d58eSHerve Codina 11663178d58eSHerve Codina return 0; 11673178d58eSHerve Codina } 11683178d58eSHerve Codina 11693178d58eSHerve Codina static int qmc_setup_ints(struct qmc *qmc) 11703178d58eSHerve Codina { 11713178d58eSHerve Codina unsigned int i; 11723178d58eSHerve Codina u16 __iomem *last; 11733178d58eSHerve Codina 11743178d58eSHerve Codina /* Raz all entries */ 11753178d58eSHerve Codina for (i = 0; i < (qmc->int_size / sizeof(u16)); i++) 11763178d58eSHerve Codina qmc_write16(qmc->int_table + i, 0x0000); 11773178d58eSHerve Codina 11783178d58eSHerve Codina /* Set Wrap bit on last entry */ 11793178d58eSHerve Codina if (qmc->int_size >= sizeof(u16)) { 11803178d58eSHerve Codina last = qmc->int_table + (qmc->int_size / sizeof(u16)) - 1; 11813178d58eSHerve Codina qmc_write16(last, QMC_INT_W); 11823178d58eSHerve Codina } 11833178d58eSHerve Codina 11843178d58eSHerve Codina return 0; 11853178d58eSHerve Codina } 11863178d58eSHerve Codina 11873178d58eSHerve Codina static void qmc_irq_gint(struct qmc *qmc) 11883178d58eSHerve Codina { 11893178d58eSHerve Codina struct qmc_chan *chan; 11903178d58eSHerve Codina unsigned int chan_id; 11913178d58eSHerve Codina unsigned long flags; 11923178d58eSHerve Codina u16 int_entry; 11933178d58eSHerve Codina 11943178d58eSHerve Codina int_entry = qmc_read16(qmc->int_curr); 11953178d58eSHerve Codina while (int_entry & QMC_INT_V) { 11963178d58eSHerve Codina /* Clear all but the Wrap bit */ 11973178d58eSHerve Codina qmc_write16(qmc->int_curr, int_entry & QMC_INT_W); 11983178d58eSHerve Codina 11993178d58eSHerve Codina chan_id = QMC_INT_GET_CHANNEL(int_entry); 12003178d58eSHerve Codina chan = qmc->chans[chan_id]; 12013178d58eSHerve Codina if (!chan) { 12023178d58eSHerve Codina dev_err(qmc->dev, "interrupt on invalid chan %u\n", chan_id); 12033178d58eSHerve Codina goto int_next; 12043178d58eSHerve Codina } 12053178d58eSHerve Codina 12063178d58eSHerve Codina if (int_entry & QMC_INT_TXB) 12073178d58eSHerve Codina qmc_chan_write_done(chan); 12083178d58eSHerve Codina 12093178d58eSHerve Codina if (int_entry & QMC_INT_UN) { 12103178d58eSHerve Codina dev_info(qmc->dev, "intr chan %u, 0x%04x (UN)\n", chan_id, 12113178d58eSHerve Codina int_entry); 12123178d58eSHerve Codina chan->nb_tx_underrun++; 12133178d58eSHerve Codina } 12143178d58eSHerve Codina 12153178d58eSHerve Codina if (int_entry & QMC_INT_BSY) { 12163178d58eSHerve Codina dev_info(qmc->dev, "intr chan %u, 0x%04x (BSY)\n", chan_id, 12173178d58eSHerve Codina int_entry); 12183178d58eSHerve Codina chan->nb_rx_busy++; 12193178d58eSHerve Codina /* Restart the receiver if needed */ 12203178d58eSHerve Codina spin_lock_irqsave(&chan->rx_lock, flags); 12213178d58eSHerve Codina if (chan->rx_pending && !chan->is_rx_stopped) { 12223178d58eSHerve Codina if (chan->mode == QMC_TRANSPARENT) 12233178d58eSHerve Codina qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x18000080); 12243178d58eSHerve Codina else 12253178d58eSHerve Codina qmc_write32(chan->s_param + QMC_SPE_ZDSTATE, 0x00000080); 12263178d58eSHerve Codina qmc_write32(chan->s_param + QMC_SPE_RSTATE, 0x31000000); 12273178d58eSHerve Codina chan->is_rx_halted = false; 12283178d58eSHerve Codina } else { 12293178d58eSHerve Codina chan->is_rx_halted = true; 12303178d58eSHerve Codina } 12313178d58eSHerve Codina spin_unlock_irqrestore(&chan->rx_lock, flags); 12323178d58eSHerve Codina } 12333178d58eSHerve Codina 12343178d58eSHerve Codina if (int_entry & QMC_INT_RXB) 12353178d58eSHerve Codina qmc_chan_read_done(chan); 12363178d58eSHerve Codina 12373178d58eSHerve Codina int_next: 12383178d58eSHerve Codina if (int_entry & QMC_INT_W) 12393178d58eSHerve Codina qmc->int_curr = qmc->int_table; 12403178d58eSHerve Codina else 12413178d58eSHerve Codina qmc->int_curr++; 12423178d58eSHerve Codina int_entry = qmc_read16(qmc->int_curr); 12433178d58eSHerve Codina } 12443178d58eSHerve Codina } 12453178d58eSHerve Codina 12463178d58eSHerve Codina static irqreturn_t qmc_irq_handler(int irq, void *priv) 12473178d58eSHerve Codina { 12483178d58eSHerve Codina struct qmc *qmc = (struct qmc *)priv; 12493178d58eSHerve Codina u16 scce; 12503178d58eSHerve Codina 12513178d58eSHerve Codina scce = qmc_read16(qmc->scc_regs + SCC_SCCE); 12523178d58eSHerve Codina qmc_write16(qmc->scc_regs + SCC_SCCE, scce); 12533178d58eSHerve Codina 12543178d58eSHerve Codina if (unlikely(scce & SCC_SCCE_IQOV)) 12553178d58eSHerve Codina dev_info(qmc->dev, "IRQ queue overflow\n"); 12563178d58eSHerve Codina 12573178d58eSHerve Codina if (unlikely(scce & SCC_SCCE_GUN)) 12583178d58eSHerve Codina dev_err(qmc->dev, "Global transmitter underrun\n"); 12593178d58eSHerve Codina 12603178d58eSHerve Codina if (unlikely(scce & SCC_SCCE_GOV)) 12613178d58eSHerve Codina dev_err(qmc->dev, "Global receiver overrun\n"); 12623178d58eSHerve Codina 12633178d58eSHerve Codina /* normal interrupt */ 12643178d58eSHerve Codina if (likely(scce & SCC_SCCE_GINT)) 12653178d58eSHerve Codina qmc_irq_gint(qmc); 12663178d58eSHerve Codina 12673178d58eSHerve Codina return IRQ_HANDLED; 12683178d58eSHerve Codina } 12693178d58eSHerve Codina 12703178d58eSHerve Codina static int qmc_probe(struct platform_device *pdev) 12713178d58eSHerve Codina { 12723178d58eSHerve Codina struct device_node *np = pdev->dev.of_node; 12733178d58eSHerve Codina unsigned int nb_chans; 12743178d58eSHerve Codina struct resource *res; 12753178d58eSHerve Codina struct qmc *qmc; 12763178d58eSHerve Codina int irq; 12773178d58eSHerve Codina int ret; 12783178d58eSHerve Codina 12793178d58eSHerve Codina qmc = devm_kzalloc(&pdev->dev, sizeof(*qmc), GFP_KERNEL); 12803178d58eSHerve Codina if (!qmc) 12813178d58eSHerve Codina return -ENOMEM; 12823178d58eSHerve Codina 12833178d58eSHerve Codina qmc->dev = &pdev->dev; 12843178d58eSHerve Codina INIT_LIST_HEAD(&qmc->chan_head); 12853178d58eSHerve Codina 12863178d58eSHerve Codina qmc->scc_regs = devm_platform_ioremap_resource_byname(pdev, "scc_regs"); 12873178d58eSHerve Codina if (IS_ERR(qmc->scc_regs)) 12883178d58eSHerve Codina return PTR_ERR(qmc->scc_regs); 12893178d58eSHerve Codina 12903178d58eSHerve Codina 12913178d58eSHerve Codina res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "scc_pram"); 12923178d58eSHerve Codina if (!res) 12933178d58eSHerve Codina return -EINVAL; 12943178d58eSHerve Codina qmc->scc_pram_offset = res->start - get_immrbase(); 12953178d58eSHerve Codina qmc->scc_pram = devm_ioremap_resource(qmc->dev, res); 12963178d58eSHerve Codina if (IS_ERR(qmc->scc_pram)) 12973178d58eSHerve Codina return PTR_ERR(qmc->scc_pram); 12983178d58eSHerve Codina 12993178d58eSHerve Codina qmc->dpram = devm_platform_ioremap_resource_byname(pdev, "dpram"); 13003178d58eSHerve Codina if (IS_ERR(qmc->dpram)) 13013178d58eSHerve Codina return PTR_ERR(qmc->dpram); 13023178d58eSHerve Codina 13033178d58eSHerve Codina qmc->tsa_serial = devm_tsa_serial_get_byphandle(qmc->dev, np, "fsl,tsa-serial"); 13043178d58eSHerve Codina if (IS_ERR(qmc->tsa_serial)) { 13053178d58eSHerve Codina return dev_err_probe(qmc->dev, PTR_ERR(qmc->tsa_serial), 13063178d58eSHerve Codina "Failed to get TSA serial\n"); 13073178d58eSHerve Codina } 13083178d58eSHerve Codina 13093178d58eSHerve Codina /* Connect the serial (SCC) to TSA */ 13103178d58eSHerve Codina ret = tsa_serial_connect(qmc->tsa_serial); 13113178d58eSHerve Codina if (ret) { 13123178d58eSHerve Codina dev_err(qmc->dev, "Failed to connect TSA serial\n"); 13133178d58eSHerve Codina return ret; 13143178d58eSHerve Codina } 13153178d58eSHerve Codina 13163178d58eSHerve Codina /* Parse channels informationss */ 13173178d58eSHerve Codina ret = qmc_of_parse_chans(qmc, np); 13183178d58eSHerve Codina if (ret) 13193178d58eSHerve Codina goto err_tsa_serial_disconnect; 13203178d58eSHerve Codina 13213178d58eSHerve Codina nb_chans = qmc_nb_chans(qmc); 13223178d58eSHerve Codina 13233178d58eSHerve Codina /* Init GMSR_H and GMSR_L registers */ 13243178d58eSHerve Codina qmc_write32(qmc->scc_regs + SCC_GSMRH, 13253178d58eSHerve Codina SCC_GSMRH_CDS | SCC_GSMRH_CTSS | SCC_GSMRH_CDP | SCC_GSMRH_CTSP); 13263178d58eSHerve Codina 13273178d58eSHerve Codina /* enable QMC mode */ 13283178d58eSHerve Codina qmc_write32(qmc->scc_regs + SCC_GSMRL, SCC_GSMRL_MODE_QMC); 13293178d58eSHerve Codina 13303178d58eSHerve Codina /* 13313178d58eSHerve Codina * Allocate the buffer descriptor table 13323178d58eSHerve Codina * 8 rx and 8 tx descriptors per channel 13333178d58eSHerve Codina */ 13343178d58eSHerve Codina qmc->bd_size = (nb_chans * (QMC_NB_TXBDS + QMC_NB_RXBDS)) * sizeof(cbd_t); 13353178d58eSHerve Codina qmc->bd_table = dmam_alloc_coherent(qmc->dev, qmc->bd_size, 13363178d58eSHerve Codina &qmc->bd_dma_addr, GFP_KERNEL); 13373178d58eSHerve Codina if (!qmc->bd_table) { 13383178d58eSHerve Codina dev_err(qmc->dev, "Failed to allocate bd table\n"); 13393178d58eSHerve Codina ret = -ENOMEM; 13403178d58eSHerve Codina goto err_tsa_serial_disconnect; 13413178d58eSHerve Codina } 13423178d58eSHerve Codina memset(qmc->bd_table, 0, qmc->bd_size); 13433178d58eSHerve Codina 13443178d58eSHerve Codina qmc_write32(qmc->scc_pram + QMC_GBL_MCBASE, qmc->bd_dma_addr); 13453178d58eSHerve Codina 13463178d58eSHerve Codina /* Allocate the interrupt table */ 13473178d58eSHerve Codina qmc->int_size = QMC_NB_INTS * sizeof(u16); 13483178d58eSHerve Codina qmc->int_table = dmam_alloc_coherent(qmc->dev, qmc->int_size, 13493178d58eSHerve Codina &qmc->int_dma_addr, GFP_KERNEL); 13503178d58eSHerve Codina if (!qmc->int_table) { 13513178d58eSHerve Codina dev_err(qmc->dev, "Failed to allocate interrupt table\n"); 13523178d58eSHerve Codina ret = -ENOMEM; 13533178d58eSHerve Codina goto err_tsa_serial_disconnect; 13543178d58eSHerve Codina } 13553178d58eSHerve Codina memset(qmc->int_table, 0, qmc->int_size); 13563178d58eSHerve Codina 13573178d58eSHerve Codina qmc->int_curr = qmc->int_table; 13583178d58eSHerve Codina qmc_write32(qmc->scc_pram + QMC_GBL_INTBASE, qmc->int_dma_addr); 13593178d58eSHerve Codina qmc_write32(qmc->scc_pram + QMC_GBL_INTPTR, qmc->int_dma_addr); 13603178d58eSHerve Codina 13613178d58eSHerve Codina /* Set MRBLR (valid for HDLC only) max MRU + max CRC */ 13623178d58eSHerve Codina qmc_write16(qmc->scc_pram + QMC_GBL_MRBLR, HDLC_MAX_MRU + 4); 13633178d58eSHerve Codina 13643178d58eSHerve Codina qmc_write16(qmc->scc_pram + QMC_GBL_GRFTHR, 1); 13653178d58eSHerve Codina qmc_write16(qmc->scc_pram + QMC_GBL_GRFCNT, 1); 13663178d58eSHerve Codina 13673178d58eSHerve Codina qmc_write32(qmc->scc_pram + QMC_GBL_C_MASK32, 0xDEBB20E3); 13683178d58eSHerve Codina qmc_write16(qmc->scc_pram + QMC_GBL_C_MASK16, 0xF0B8); 13693178d58eSHerve Codina 13703178d58eSHerve Codina ret = qmc_setup_tsa(qmc); 13713178d58eSHerve Codina if (ret) 13723178d58eSHerve Codina goto err_tsa_serial_disconnect; 13733178d58eSHerve Codina 13743178d58eSHerve Codina qmc_write16(qmc->scc_pram + QMC_GBL_QMCSTATE, 0x8000); 13753178d58eSHerve Codina 13763178d58eSHerve Codina ret = qmc_setup_chans(qmc); 13773178d58eSHerve Codina if (ret) 13783178d58eSHerve Codina goto err_tsa_serial_disconnect; 13793178d58eSHerve Codina 13803178d58eSHerve Codina /* Init interrupts table */ 13813178d58eSHerve Codina ret = qmc_setup_ints(qmc); 13823178d58eSHerve Codina if (ret) 13833178d58eSHerve Codina goto err_tsa_serial_disconnect; 13843178d58eSHerve Codina 13853178d58eSHerve Codina /* Disable and clear interrupts, set the irq handler */ 13863178d58eSHerve Codina qmc_write16(qmc->scc_regs + SCC_SCCM, 0x0000); 13873178d58eSHerve Codina qmc_write16(qmc->scc_regs + SCC_SCCE, 0x000F); 13883178d58eSHerve Codina irq = platform_get_irq(pdev, 0); 13893178d58eSHerve Codina if (irq < 0) 13903178d58eSHerve Codina goto err_tsa_serial_disconnect; 13913178d58eSHerve Codina ret = devm_request_irq(qmc->dev, irq, qmc_irq_handler, 0, "qmc", qmc); 13923178d58eSHerve Codina if (ret < 0) 13933178d58eSHerve Codina goto err_tsa_serial_disconnect; 13943178d58eSHerve Codina 13953178d58eSHerve Codina /* Enable interrupts */ 13963178d58eSHerve Codina qmc_write16(qmc->scc_regs + SCC_SCCM, 13973178d58eSHerve Codina SCC_SCCE_IQOV | SCC_SCCE_GINT | SCC_SCCE_GUN | SCC_SCCE_GOV); 13983178d58eSHerve Codina 13993178d58eSHerve Codina ret = qmc_finalize_chans(qmc); 14003178d58eSHerve Codina if (ret < 0) 14013178d58eSHerve Codina goto err_disable_intr; 14023178d58eSHerve Codina 14033178d58eSHerve Codina /* Enable transmiter and receiver */ 14043178d58eSHerve Codina qmc_setbits32(qmc->scc_regs + SCC_GSMRL, SCC_GSMRL_ENR | SCC_GSMRL_ENT); 14053178d58eSHerve Codina 14063178d58eSHerve Codina platform_set_drvdata(pdev, qmc); 14073178d58eSHerve Codina 14083178d58eSHerve Codina return 0; 14093178d58eSHerve Codina 14103178d58eSHerve Codina err_disable_intr: 14113178d58eSHerve Codina qmc_write16(qmc->scc_regs + SCC_SCCM, 0); 14123178d58eSHerve Codina 14133178d58eSHerve Codina err_tsa_serial_disconnect: 14143178d58eSHerve Codina tsa_serial_disconnect(qmc->tsa_serial); 14153178d58eSHerve Codina return ret; 14163178d58eSHerve Codina } 14173178d58eSHerve Codina 14183178d58eSHerve Codina static int qmc_remove(struct platform_device *pdev) 14193178d58eSHerve Codina { 14203178d58eSHerve Codina struct qmc *qmc = platform_get_drvdata(pdev); 14213178d58eSHerve Codina 14223178d58eSHerve Codina /* Disable transmiter and receiver */ 14233178d58eSHerve Codina qmc_setbits32(qmc->scc_regs + SCC_GSMRL, 0); 14243178d58eSHerve Codina 14253178d58eSHerve Codina /* Disable interrupts */ 14263178d58eSHerve Codina qmc_write16(qmc->scc_regs + SCC_SCCM, 0); 14273178d58eSHerve Codina 14283178d58eSHerve Codina /* Disconnect the serial from TSA */ 14293178d58eSHerve Codina tsa_serial_disconnect(qmc->tsa_serial); 14303178d58eSHerve Codina 14313178d58eSHerve Codina return 0; 14323178d58eSHerve Codina } 14333178d58eSHerve Codina 14343178d58eSHerve Codina static const struct of_device_id qmc_id_table[] = { 14353178d58eSHerve Codina { .compatible = "fsl,cpm1-scc-qmc" }, 14363178d58eSHerve Codina {} /* sentinel */ 14373178d58eSHerve Codina }; 14383178d58eSHerve Codina MODULE_DEVICE_TABLE(of, qmc_id_table); 14393178d58eSHerve Codina 14403178d58eSHerve Codina static struct platform_driver qmc_driver = { 14413178d58eSHerve Codina .driver = { 14423178d58eSHerve Codina .name = "fsl-qmc", 14433178d58eSHerve Codina .of_match_table = of_match_ptr(qmc_id_table), 14443178d58eSHerve Codina }, 14453178d58eSHerve Codina .probe = qmc_probe, 14463178d58eSHerve Codina .remove = qmc_remove, 14473178d58eSHerve Codina }; 14483178d58eSHerve Codina module_platform_driver(qmc_driver); 14493178d58eSHerve Codina 14503178d58eSHerve Codina struct qmc_chan *qmc_chan_get_byphandle(struct device_node *np, const char *phandle_name) 14513178d58eSHerve Codina { 14523178d58eSHerve Codina struct of_phandle_args out_args; 14533178d58eSHerve Codina struct platform_device *pdev; 14543178d58eSHerve Codina struct qmc_chan *qmc_chan; 14553178d58eSHerve Codina struct qmc *qmc; 14563178d58eSHerve Codina int ret; 14573178d58eSHerve Codina 14583178d58eSHerve Codina ret = of_parse_phandle_with_fixed_args(np, phandle_name, 1, 0, 14593178d58eSHerve Codina &out_args); 14603178d58eSHerve Codina if (ret < 0) 14613178d58eSHerve Codina return ERR_PTR(ret); 14623178d58eSHerve Codina 14633178d58eSHerve Codina if (!of_match_node(qmc_driver.driver.of_match_table, out_args.np)) { 14643178d58eSHerve Codina of_node_put(out_args.np); 14653178d58eSHerve Codina return ERR_PTR(-EINVAL); 14663178d58eSHerve Codina } 14673178d58eSHerve Codina 14683178d58eSHerve Codina pdev = of_find_device_by_node(out_args.np); 14693178d58eSHerve Codina of_node_put(out_args.np); 14703178d58eSHerve Codina if (!pdev) 14713178d58eSHerve Codina return ERR_PTR(-ENODEV); 14723178d58eSHerve Codina 14733178d58eSHerve Codina qmc = platform_get_drvdata(pdev); 14743178d58eSHerve Codina if (!qmc) { 14753178d58eSHerve Codina platform_device_put(pdev); 14763178d58eSHerve Codina return ERR_PTR(-EPROBE_DEFER); 14773178d58eSHerve Codina } 14783178d58eSHerve Codina 14793178d58eSHerve Codina if (out_args.args_count != 1) { 14803178d58eSHerve Codina platform_device_put(pdev); 14813178d58eSHerve Codina return ERR_PTR(-EINVAL); 14823178d58eSHerve Codina } 14833178d58eSHerve Codina 14843178d58eSHerve Codina if (out_args.args[0] >= ARRAY_SIZE(qmc->chans)) { 14853178d58eSHerve Codina platform_device_put(pdev); 14863178d58eSHerve Codina return ERR_PTR(-EINVAL); 14873178d58eSHerve Codina } 14883178d58eSHerve Codina 14893178d58eSHerve Codina qmc_chan = qmc->chans[out_args.args[0]]; 14903178d58eSHerve Codina if (!qmc_chan) { 14913178d58eSHerve Codina platform_device_put(pdev); 14923178d58eSHerve Codina return ERR_PTR(-ENOENT); 14933178d58eSHerve Codina } 14943178d58eSHerve Codina 14953178d58eSHerve Codina return qmc_chan; 14963178d58eSHerve Codina } 14973178d58eSHerve Codina EXPORT_SYMBOL(qmc_chan_get_byphandle); 14983178d58eSHerve Codina 14993178d58eSHerve Codina void qmc_chan_put(struct qmc_chan *chan) 15003178d58eSHerve Codina { 15013178d58eSHerve Codina put_device(chan->qmc->dev); 15023178d58eSHerve Codina } 15033178d58eSHerve Codina EXPORT_SYMBOL(qmc_chan_put); 15043178d58eSHerve Codina 15053178d58eSHerve Codina static void devm_qmc_chan_release(struct device *dev, void *res) 15063178d58eSHerve Codina { 15073178d58eSHerve Codina struct qmc_chan **qmc_chan = res; 15083178d58eSHerve Codina 15093178d58eSHerve Codina qmc_chan_put(*qmc_chan); 15103178d58eSHerve Codina } 15113178d58eSHerve Codina 15123178d58eSHerve Codina struct qmc_chan *devm_qmc_chan_get_byphandle(struct device *dev, 15133178d58eSHerve Codina struct device_node *np, 15143178d58eSHerve Codina const char *phandle_name) 15153178d58eSHerve Codina { 15163178d58eSHerve Codina struct qmc_chan *qmc_chan; 15173178d58eSHerve Codina struct qmc_chan **dr; 15183178d58eSHerve Codina 15193178d58eSHerve Codina dr = devres_alloc(devm_qmc_chan_release, sizeof(*dr), GFP_KERNEL); 15203178d58eSHerve Codina if (!dr) 15213178d58eSHerve Codina return ERR_PTR(-ENOMEM); 15223178d58eSHerve Codina 15233178d58eSHerve Codina qmc_chan = qmc_chan_get_byphandle(np, phandle_name); 15243178d58eSHerve Codina if (!IS_ERR(qmc_chan)) { 15253178d58eSHerve Codina *dr = qmc_chan; 15263178d58eSHerve Codina devres_add(dev, dr); 15273178d58eSHerve Codina } else { 15283178d58eSHerve Codina devres_free(dr); 15293178d58eSHerve Codina } 15303178d58eSHerve Codina 15313178d58eSHerve Codina return qmc_chan; 15323178d58eSHerve Codina } 15333178d58eSHerve Codina EXPORT_SYMBOL(devm_qmc_chan_get_byphandle); 15343178d58eSHerve Codina 15353178d58eSHerve Codina MODULE_AUTHOR("Herve Codina <herve.codina@bootlin.com>"); 15363178d58eSHerve Codina MODULE_DESCRIPTION("CPM QMC driver"); 15373178d58eSHerve Codina MODULE_LICENSE("GPL"); 1538