⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dm355_spi_master.c

📁 TI的达芬奇系列dm355使用的spi模块驱动
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * DM355 SPI controller driver with Interrupt.*/#include "dm355_spi_master.h"#if defined(CONFIG_SPI_DEBUG)#define DEBUG_SPI(fmt,arg...)  printk(KERN_EMERG fmt , ##arg);#else#define DEBUG_SPI(fmt,arg...)#endif#define ENTER DEBUG_SPI("[Ei %s-%d] \n", __FUNCTION__, __LINE__);#define EXIT  DEBUG_SPI("[Ex %s-%d] \n", __FUNCTION__, __LINE__);/* operating momde selection from kconfig */dm355_spi_config_t dm355_spi_config;#define dm355_SPI_RX_BUF(type) 					  \static inline void dm355_spi_rx_buf_##type(u32 data, struct dm355_spi *dm355_spi) \{									  \	type * rx = dm355_spi->rx;					  \	*rx++ = (type)data;						  \	dm355_spi->rx = rx;						  \}#define dm355_SPI_TX_BUF(type)				\static inline u32 dm355_spi_tx_buf_##type(struct dm355_spi *dm355_spi)	\{								\	u32 data;						\	const type * tx = dm355_spi->tx;			\	data = *tx++;						\	dm355_spi->tx = tx;					\	return data;						\}dm355_SPI_RX_BUF(u8);dm355_SPI_RX_BUF(u16);dm355_SPI_TX_BUF(u8);dm355_SPI_TX_BUF(u16);#define SP0_MUX_SEL_LINE \PINMUX3 |= 0x10000000;\PINMUX4 &= 0xfffffffc#define SP1_MUX_SEL_LINE \PINMUX3 |= 0x0f800000#define SP2_MUX_SEL_LINE \PINMUX0 |= 0xeA/* * Interface to control the chip select signal */static void dm355_spi_chipselect(struct spi_device *spi, int value){        struct dm355_spi *dm355_spi;        ENTER dm355_spi = spi_master_get_devdata(spi->master);        EXIT            /* board specific chip select logic decides the polarity and cs line for the controller */            if (value == BITBANG_CS_ACTIVE)                return;        else                return;}/** * dm355_spi_setup_transfer - This functions will determine transfer method * @spi: spi device on which data transfer to be done * @t: spi transfer in which transfer info is filled * * This function determines data transfer method (8/16/32 bit transfer). * It will also set the SPI Clock Control register according to  * SPI slave device freq. */static int dm355_spi_setup_transfer(struct spi_device *spi,                                    struct spi_transfer *t){        struct dm355_spi *dm355_spi;        u8 bits_per_word = 0;        u32 hz = 0;        int i = 0;        ENTER dm355_spi = spi_master_get_devdata(spi->master);        spi->controller_data = NULL;        spi->controller_data = &dm355_spi_config;        if (t) {                bits_per_word = t->bits_per_word;                hz = t->speed_hz;        }        /* if bits_per_word is not set then set it default */        if (!bits_per_word)                bits_per_word = spi->bits_per_word;        /* Assign function pointer to appropriate transfer method 8bit/16bit or 32bit transfer */        if (bits_per_word <= 8 && bits_per_word >= 2) {                DEBUG_SPI("BITS PER WORD = %d\n", bits_per_word);                dm355_spi->get_rx = dm355_spi_rx_buf_u8;                dm355_spi->get_tx = dm355_spi_tx_buf_u8;                dm355_spi->slave[spi->chip_select].bytes_per_word = 1;        } else if (bits_per_word <= 16 && bits_per_word >= 2) {                DEBUG_SPI("BITS PER WORD = %d\n", bits_per_word);                dm355_spi->get_rx = dm355_spi_rx_buf_u16;                dm355_spi->get_tx = dm355_spi_tx_buf_u16;                dm355_spi->slave[spi->chip_select].bytes_per_word = 2;        } else                return ERROR;        if (!hz) {                hz = spi->max_speed_hz;                if (!hz) {                        hz = 2000000;   /* defaulting to 2Mhz */                        printk                            ("[SPI] -> Slave device speed not set correctly. Trying with %dHz\n",                             hz);                }        }/**************************************************************************/        for (i = 0; i < 4; i++) {                dm355_spi->base->SPIFMT[i] &= ~(SPI_SPIFMT_CHARLEN_MASK);                dm355_spi->base->SPIFMT[i] |= bits_per_word;        }        EXIT return 0;}/** * dm355_spi_setup - This functions will set default transfer method * @spi: spi device on which data transfer to be done * * This functions sets the default transfer method. */static int dm355_spi_setup(struct spi_device *spi){        int retval;        struct dm355_spi *dm355_spi;        ENTER dm355_spi = spi_master_get_devdata(spi->master);        /*if bits per word length is zero then set it default 8 */        if (!spi->bits_per_word)                spi->bits_per_word = 8;        dm355_spi->slave[spi->chip_select].cmd_to_write = 0;        retval = dm355_spi_setup_transfer(spi, NULL);        EXIT return retval;}/** * dm355_spi_bufs - functions which will handle transfer data * @spi: spi device on which data transfer to be done * @t: spi transfer in which transfer info is filled * * This function will put data to be transferred into data register * of SPI controller and then wait untill the completion will be marked * by the IRQ Handler. */#define BIT_CLEAR_TIME_OUT	10000/* #define SPI_PROFILE 1 */#ifdef SPI_PROFILEstatic unsigned int spi_prof_start;static unsigned int spi_prof_end;static unsigned int spi_avg_latency;#define rdtscl(dest) \	    __asm__ __volatile__("mfc0 %0,$9; nop" : "=r" (dest))static void calculate_spi_latency(void){        unsigned int diff = spi_prof_end - spi_prof_start;        if (diff < 0) {                printk("Count register wraparound not supported.\n");        } else {                if (spi_avg_latency == 0) {                        spi_avg_latency = diff;                } else {                        spi_avg_latency += diff;                        spi_avg_latency /= 2;                }        }}void spi_start_profile(void){        rdtscl(spi_prof_start);}void spi_end_profile(void){        rdtscl(spi_prof_end);        calculate_spi_latency();        DEBUG_SPI("[SPI-PROFILE] Throughput = %d\n", spi_avg_latency);}unsigned int spi_get_avg_latency(){        return spi_avg_latency;}#endif                          /* SPI_PROFILE */static int dm355_spi_bufs(struct spi_device *spi, struct spi_transfer *t){        struct dm355_spi *dm355_spi;        int i, intStatus = 0;        u8 conv = 1;        u32 tx_data = 0;        u32 data1_reg_val = 0;        dm355_spi_config_t *spi_cfg;        u32 rx_data = 0;        u32 sPIPC0 = 0;        volatile u32 buf_val, flg_val;        ENTER dm355_spi = spi_master_get_devdata(spi->master);        dm355_spi->tx = t->tx_buf;        dm355_spi->rx = t->rx_buf;        //DEBUG_SPI("tx_buf value = %x\n",*(u16 *)dm355_spi->tx);        /* convert len to words bbased on bits_per_word */        conv = dm355_spi->slave[spi->chip_select].bytes_per_word;        dm355_spi->count = t->len / conv;        DEBUG_SPI("chipselect=%d, bytes_per_word=%d, t->len=%d, conv=%d\n",              spi->chip_select,              dm355_spi->slave[spi->chip_select].bytes_per_word, t->len,              conv);        INIT_COMPLETION(dm355_spi->done);        /*configuraton parameter for SPI */        spi_cfg = (dm355_spi_config_t *) spi->controller_data;        for (i = 0; i < 4; i++) {                if (spi_cfg->phaseIn)                        dm355_spi->base->SPIFMT[i] |=                            SPI_SPIFMT_PHASE_MASK;                else                        dm355_spi->base->SPIFMT[i] &=                            ~(SPI_SPIFMT_PHASE_MASK);                if (spi_cfg->clkHigh)                        dm355_spi->base->SPIFMT[i] |=                            SPI_SPIFMT_POLARITY_MASK;                else                        dm355_spi->base->SPIFMT[i] &=                            ~(SPI_SPIFMT_POLARITY_MASK);                if (spi_cfg->lsbFirst)                        dm355_spi->base->SPIFMT[i] |=                            SPI_SPIFMT_SHIFTDIR_MASK;                else                        dm355_spi->base->SPIFMT[i] &=                            ~(SPI_SPIFMT_SHIFTDIR_MASK);        }        /*Enable SPI */        dm355_spi->base->SPIGCR1 |= SPI_SPIGCR1_SPIENA_MASK;        /*Clock internal */        if (spi_cfg->clkInternal)                dm355_spi->base->SPIGCR1 |= SPI_SPIGCR1_CLKMOD_MASK;        else                dm355_spi->base->SPIGCR1 &= ~(SPI_SPIGCR1_CLKMOD_MASK);        /* master mode default */        dm355_spi->base->SPIGCR1 |= SPI_SPIGCR1_MASTER_MASK;        /*CD default = 0xFF */        dm355_spi->base->SPIDEF |= CS_DEFAULT;        if (spi_cfg->intrLevel)                dm355_spi->base->SPILVL = SPI_INTLVL_1;        else                dm355_spi->base->SPILVL = SPI_INTLVL_0;        switch (spi_cfg->pinOpModes) {        case SPI_OPMODE_3PIN:                sPIPC0 |= (SPI_SPIPC0_DIFUN_DI << SPI_SPIPC0_DIFUN_SHIFT)                    | (SPI_SPIPC0_DOFUN_DO << SPI_SPIPC0_DOFUN_SHIFT)                    | (SPI_SPIPC0_CLKFUN_CLK << SPI_SPIPC0_CLKFUN_SHIFT);                dm355_spi->base->SPIPC0 = sPIPC0;                break;        case SPI_OPMODE_SPISCS_4PIN:                sPIPC0 |= (SPI_SPIPC0_DIFUN_DI << SPI_SPIPC0_DIFUN_SHIFT)                    | (SPI_SPIPC0_DOFUN_DO << SPI_SPIPC0_DOFUN_SHIFT)                    | (SPI_SPIPC0_CLKFUN_CLK << SPI_SPIPC0_CLKFUN_SHIFT)                    | (SPI_SPIPC0_EN1FUN_EN1 << SPI_SPIPC0_EN1FUN_SHIFT)                    | (SPI_SPIPC0_EN0FUN_EN0 << SPI_SPIPC0_EN0FUN_SHIFT);                dm355_spi->base->SPIPC0 = sPIPC0;                break;        case SPI_OPMODE_SPIENA_4PIN:                sPIPC0 |= (SPI_SPIPC0_DIFUN_DI << SPI_SPIPC0_DIFUN_SHIFT)                    | (SPI_SPIPC0_DOFUN_DO << SPI_SPIPC0_DOFUN_SHIFT)                    | (SPI_SPIPC0_CLKFUN_CLK << SPI_SPIPC0_CLKFUN_SHIFT)                    | (SPI_SPIPC0_SPIENA << SPI_SPIPC0_SPIENA_SHIFT);                dm355_spi->base->SPIPC0 = sPIPC0;                break;        default:                return -1;        }        if (spi_cfg->loopBack)                dm355_spi->base->SPIGCR1 |= SPI_SPIGCR1_LOOPBACK_MASK;        else                dm355_spi->base->SPIGCR1 &= ~(SPI_SPIGCR1_LOOPBACK_MASK);        /*Put delay val if required */        dm355_spi->base->SPIDELAY = 0                | ( 8 << 24 )   // C2TDELAY                | ( 8 << 16 );  // T2CDELAY                data1_reg_val |=                    spi_cfg->csHold << SPI_SPIDAT1_CSHOLD_SHIFT;                data1_reg_val |=            /*spi->chip_select*/2 << SPI_SPIDAT1_CSNR_SHIFT;        /* Determine the command to execute READ or WRITE */        if (t->tx_buf) {                u8 flag = 0;                /* set the flag for DM355_EEPROM_READ */                if ( t->len == 3 && ((u8 *)t->tx_buf)[0] == 0x3 )                    flag = 1;                dm355_spi->base->SPIINT &= ~(SPI_SPIINT_MASKALL);                i = 0;                dm355_spi->base->SPIBUF;                while (1) {                        buf_val = dm355_spi->base->SPIBUF;                        if ((buf_val & SPI_SPIBUF_TXFULL_MASK) == FALSE) {                                tx_data = dm355_spi->get_tx(dm355_spi);                                DEBUG_SPI("data to be TX = 0x%x\n", tx_data);                                i++;                                         /* READ is treated differenetly here when count to */                                if ( i  > dm355_spi->count )                                    dm355_spi->base->SPIDAT1 = (data1_reg_val & 0x0ffcffff) | tx_data ;                                else                                    dm355_spi->base->SPIDAT1 = data1_reg_val  | tx_data ;                                DEBUG_SPI                                    ("\n***I have transmited...on iteration %d and buf_val = 0x%8x***\n",                                     i-1, buf_val);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -