1975 lines
62 KiB
C
Executable File
1975 lines
62 KiB
C
Executable File
/*
|
|
* mspi.c- Sigmastar
|
|
*
|
|
* Copyright (c) [2019~2020] SigmaStar Technology.
|
|
*
|
|
*
|
|
* This software is licensed under the terms of the GNU General Public
|
|
* License version 2, as published by the Free Software Foundation, and
|
|
* may be copied, distributed, and modified under those terms.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License version 2 for more details.
|
|
*
|
|
*/
|
|
#include <linux/clk.h>
|
|
#include <linux/completion.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/err.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/io.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/module.h>
|
|
#include <linux/of.h>
|
|
#include <linux/of_irq.h>
|
|
#include <linux/of_device.h>
|
|
#include <linux/spi/spi.h>
|
|
#include <linux/gpio.h>
|
|
#include <linux/clk.h>
|
|
#include <linux/clk-provider.h>
|
|
#include <linux/dma-mapping.h>
|
|
#include "ms_platform.h"
|
|
|
|
#if defined(CONFIG_MS_PADMUX)
|
|
#include "mdrv_padmux.h"
|
|
#include "mdrv_puse.h"
|
|
#include "gpio.h"
|
|
#endif
|
|
|
|
//-------------------------------------------------------------------------------------------------
|
|
// Global Variables
|
|
//-------------------------------------------------------------------------------------------------
|
|
|
|
bool gbInitFlag = false;
|
|
static struct mutex hal_mspi_lock;
|
|
static bool SUPPORT_DMA = true;
|
|
|
|
//-------------------------------------------------------------------------------------------------
|
|
// RegbaseAddr Disc
|
|
//-------------------------------------------------------------------------------------------------
|
|
#define mspi_dbg 1
|
|
#if mspi_dbg == 0
|
|
#define mspi_dbgmsg(args...) printk(args)
|
|
#else
|
|
#define mspi_dbgmsg(args...) do{}while(0)
|
|
#endif
|
|
|
|
#define U8 u8
|
|
#define U16 u16
|
|
#define U32 u32
|
|
#define BOOL bool
|
|
#define TRUE true
|
|
#define FALSE false
|
|
|
|
#define SUPPORT_SPI_1 0
|
|
|
|
#define MAX_SUPPORT_BITS 16
|
|
|
|
#define BANK_TO_ADDR32(b) (b<<9)
|
|
#define BANK_SIZE 0x200
|
|
|
|
#define MS_BASE_REG_RIU_PA 0x1F000000
|
|
|
|
#define MSPI0_BANK_ADDR 0x1110
|
|
#define MSPI1_BANK_ADDR 0x1111
|
|
#define CLK__BANK_ADDR 0x1038
|
|
#define CHIPTOP_BANK_ADDR 0x101E
|
|
#define MOVDMA_BANK_ADDR 0x100B
|
|
|
|
#define BASE_REG_MSPI0_ADDR MSPI0_BANK_ADDR*0x200 //GET_BASE_ADDR_BY_BANK(IO_ADDRESS(MS_BASE_REG_RIU_PA), 0x111000)
|
|
#define BASE_REG_MSPI1_ADDR MSPI1_BANK_ADDR*0x200 //GET_BASE_ADDR_BY_BANK(IO_ADDRESS(MS_BASE_REG_RIU_PA), 0x111100)
|
|
#define BASE_REG_CLK_ADDR CLK__BANK_ADDR*0x200 //GET_BASE_ADDR_BY_BANK(IO_ADDRESS(MS_BASE_REG_RIU_PA), 0x103800)
|
|
#define BASE_REG_CHIPTOP_ADDR CHIPTOP_BANK_ADDR*0x200 //GET_BASE_ADDR_BY_BANK(IO_ADDRESS(MS_BASE_REG_RIU_PA), 0x101E00)
|
|
//-------------------------------------------------------------------------------------------------
|
|
// Hardware Register Capability
|
|
//-------------------------------------------------------------------------------------------------
|
|
#define MSPI_WRITE_BUF_OFFSET 0x40
|
|
#define MSPI_READ_BUF_OFFSET 0x44
|
|
#define MSPI_WBF_SIZE_OFFSET 0x48
|
|
#define MSPI_RBF_SIZE_OFFSET 0x48
|
|
// read/ write buffer size
|
|
#define MSPI_RWSIZE_MASK 0xFF
|
|
#define MSPI_RSIZE_BIT_OFFSET 0x8
|
|
#define MAX_READ_BUF_SIZE 0x8
|
|
#define MAX_WRITE_BUF_SIZE 0x8
|
|
// CLK config
|
|
#define MSPI_CTRL_OFFSET 0x49
|
|
#define MSPI_CLK_CLOCK_OFFSET 0x49
|
|
#define MSPI_CLK_CLOCK_BIT_OFFSET 0x08
|
|
#define MSPI_CLK_CLOCK_MASK 0xFF
|
|
#define MSPI_CLK_PHASE_MASK 0x40
|
|
#define MSPI_CLK_PHASE_BIT_OFFSET 0x06
|
|
#define MSPI_CLK_POLARITY_MASK 0x80
|
|
#define MSPI_CLK_POLARITY_BIT_OFFSET 0x07
|
|
#define MSPI_CLK_PHASE_MAX 0x1
|
|
#define MSPI_CLK_POLARITY_MAX 0x1
|
|
#define MSPI_CLK_CLOCK_MAX 0x7
|
|
// DC config
|
|
#define MSPI_DC_MASK 0xFF
|
|
#define MSPI_DC_BIT_OFFSET 0x08
|
|
#define MSPI_DC_TR_START_OFFSET 0x4A
|
|
#define MSPI_DC_TRSTART_MAX 0xFF
|
|
#define MSPI_DC_TR_END_OFFSET 0x4A
|
|
#define MSPI_DC_TREND_MAX 0xFF
|
|
#define MSPI_DC_TB_OFFSET 0x4B
|
|
#define MSPI_DC_TB_MAX 0xFF
|
|
#define MSPI_DC_TRW_OFFSET 0x4B
|
|
#define MSPI_DC_TRW_MAX 0xFF
|
|
// Frame Config
|
|
#define MSPI_FRAME_WBIT_OFFSET 0x4C
|
|
#define MSPI_FRAME_RBIT_OFFSET 0x4E
|
|
#define MSPI_FRAME_BIT_MAX 0x07
|
|
#define MSPI_FRAME_BIT_MASK 0x07
|
|
#define MSPI_FRAME_BIT_FIELD 0x03
|
|
#define MSPI_LSB_FIRST_OFFSET 0x50
|
|
#define MSPI_TRIGGER_OFFSET 0x5A
|
|
#define MSPI_DONE_OFFSET 0x5B
|
|
#define MSPI_DONE_CLEAR_OFFSET 0x5C
|
|
#define MSPI_CHIP_SELECT_OFFSET 0x5F
|
|
|
|
#define MSPI_FULL_DEPLUX_RD_CNT (0x77)
|
|
#define MSPI_FULL_DEPLUX_RD00 (0x78)
|
|
#define MSPI_FULL_DEPLUX_RD01 (0x78)
|
|
#define MSPI_FULL_DEPLUX_RD02 (0x79
|
|
#define MSPI_FULL_DEPLUX_RD03 (0x79)
|
|
#define MSPI_FULL_DEPLUX_RD04 (0x7a)
|
|
#define MSPI_FULL_DEPLUX_RD05 (0x7a)
|
|
#define MSPI_FULL_DEPLUX_RD06 (0x7b)
|
|
#define MSPI_FULL_DEPLUX_RD07 (0x7b)
|
|
|
|
#define MSPI_FULL_DEPLUX_RD08 (0x7c)
|
|
#define MSPI_FULL_DEPLUX_RD09 (0x7c)
|
|
#define MSPI_FULL_DEPLUX_RD10 (0x7d)
|
|
#define MSPI_FULL_DEPLUX_RD11 (0x7d)
|
|
#define MSPI_FULL_DEPLUX_RD12 (0x7e)
|
|
#define MSPI_FULL_DEPLUX_RD13 (0x7e)
|
|
#define MSPI_FULL_DEPLUX_RD14 (0x7f)
|
|
#define MSPI_FULL_DEPLUX_RD15 (0x7f)
|
|
|
|
//chip select bit map
|
|
#define MSPI_CHIP_SELECT_MAX 0x07
|
|
// control bit
|
|
#define MSPI_DONE_FLAG 0x01
|
|
#define MSPI_TRIGGER 0x01
|
|
#define MSPI_CLEAR_DONE 0x01
|
|
#define MSPI_INT_ENABLE 0x04
|
|
#define MSPI_RESET 0x02
|
|
#define MSPI_ENABLE 0x01
|
|
|
|
// clk_mspi0
|
|
#define MSPI0_CLK_CFG 0x33//bit 2 ~bit 3
|
|
#define MSPI0_CLK_108M 0x00
|
|
#define MSPI0_CLK_54M 0x04
|
|
#define MSPI0_CLK_12M 0x08
|
|
#define MSPI0_CLK_MASK 0x0F
|
|
// clk_mspi1
|
|
#define MSPI1_CLK_CFG 0x33 //bit 10 ~bit 11
|
|
#define MSPI1_CLK_108M 0x0000
|
|
#define MSPI1_CLK_54M 0x0400
|
|
#define MSPI1_CLK_12M 0x0800
|
|
#define MSPI1_CLK_MASK 0x0F00
|
|
|
|
// clk_mspi
|
|
#define MSPI_CLK_CFG 0x33
|
|
#define MSPI_SELECT_0 0x0000
|
|
#define MSPI_SELECT_1 0x4000
|
|
#define MSPI_CLK_MASK 0xF000
|
|
|
|
//CHITOP 101E mspi mode select
|
|
#define MSPI0_MODE 0x0C //bit0~bit1
|
|
#define MSPI0_MODE_MASK 0x07
|
|
#define MSPI1_MODE 0x0C //bit4~bit5
|
|
#define MSPI1_MODE_MASK 0x70
|
|
#define EJTAG_MODE 0xF
|
|
#define EJTAG_MODE_1 0x01
|
|
#define EJTAG_MODE_2 0x02
|
|
#define EJTAG_MODE_3 0x03
|
|
#define EJTAG_MODE_MASK 0x03
|
|
|
|
//MOVDMA 100B
|
|
#define MOV_DMA_SRC_ADDR_L 0x03
|
|
#define MOV_DMA_SRC_ADDR_H 0x04
|
|
#define MOV_DMA_DST_ADDR_L 0x05
|
|
#define MOV_DMA_DST_ADDR_H 0x06
|
|
#define MOV_DMA_BYTE_CNT_L 0x07
|
|
#define MOV_DMA_BYTE_CNT_H 0x08
|
|
#define DMA_MOVE0_IRQ_CLR 0x28
|
|
#define MOV_DMA_IRQ_FINAL_STATUS 0x2A
|
|
#define DMA_MOVE0_ENABLE 0x00
|
|
#define DMA_RW 0x50 //0 for dma write to device, 1 for dma read from device
|
|
#define DMA_READ 0x01
|
|
#define DMA_WRITE 0x00
|
|
#define DMA_DEVICE_MODE 0x51
|
|
#define DMA_DEVICE_SEL 0x52
|
|
|
|
//spi dma
|
|
#define MSPI_DMA_DATA_LENGTH_L 0x30
|
|
#define MSPI_DMA_DATA_LENGTH_H 0x31
|
|
#define MSPI_DMA_ENABLE 0x32
|
|
#define MSPI_DMA_RW_MODE 0x33
|
|
#define MSPI_DMA_WRITE 0x00
|
|
#define MSPI_DMA_READ 0x01
|
|
//-------------------------------------------------------------------------------------------------
|
|
// Local Defines
|
|
//-------------------------------------------------------------------------------------------------
|
|
|
|
#define READ_BYTE(_reg) (*(volatile u8*)(_reg))
|
|
#define READ_WORD(_reg) (*(volatile u16*)(_reg))
|
|
#define READ_LONG(_reg) (*(volatile u32*)(_reg))
|
|
#define WRITE_BYTE(_reg, _val) {(*((volatile u8*)(_reg))) = (u8)(_val); }
|
|
#define WRITE_WORD(_reg, _val) {(*((volatile u16*)(_reg))) = (u16)(_val); }
|
|
#define WRITE_LONG(_reg, _val) {(*((volatile u32*)(_reg))) = (u32)(_val); }
|
|
#define WRITE_WORD_MASK(_reg, _val, _mask) {(*((volatile u16*)(_reg))) = ((*((volatile u16*)(_reg))) & ~(_mask)) | ((u16)(_val) & (_mask)); }
|
|
|
|
// read 2 byte
|
|
#define MSPI_READ(_reg_) READ_WORD(bs->VirtMspBaseAddr + ((_reg_)<<2))
|
|
// write 2 byte
|
|
#define MSPI_WRITE(_reg_, _val_) {WRITE_WORD(bs->VirtMspBaseAddr + ((_reg_)<<2), (_val_)); }
|
|
//write 2 byte mask
|
|
#define MSPI_WRITE_MASK(_reg_, _val_, mask) {WRITE_WORD_MASK(bs->VirtMspBaseAddr + ((_reg_)<<2), (_val_), (mask)); }
|
|
|
|
#define CLK_READ(_reg_) READ_WORD(bs->VirtClkBaseAddr + ((_reg_)<<2))
|
|
#define CLK_WRITE(_reg_, _val_) {WRITE_WORD(bs->VirtClkBaseAddr + ((_reg_)<<2), (_val_)); }
|
|
|
|
#define CHIPTOP_READ(_reg_) READ_WORD(bs->VirtChiptopBaseAddr + ((_reg_)<<2))
|
|
#define CHIPTOP_WRITE(_reg_, _val_) {WRITE_WORD(bs->VirtChiptopBaseAddr + ((_reg_)<<2), (_val_)); }
|
|
|
|
#define MOVDMA_READ(_reg_) READ_WORD(bs->VirtMovdmaBaseAddr + ((_reg_)<<2))
|
|
#define MOVDMA_WRITE(_reg_, _val_) {WRITE_WORD(bs->VirtMovdmaBaseAddr + ((_reg_)<<2), (_val_)); }
|
|
|
|
#define _HAL_MSPI_ClearDone() MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET,MSPI_CLEAR_DONE)
|
|
#define MAX_CHECK_CNT 2000
|
|
|
|
#define MSPI_READ_INDEX 0x0
|
|
#define MSPI_WRITE_INDEX 0x1
|
|
|
|
#define SPI_MIU0_BUS_BASE 0x20000000
|
|
#define SPI_MIU1_BUS_BASE 0xFFFFFFFF
|
|
|
|
//-------------------------------------------------------------------------------------------------
|
|
// Local Variables
|
|
//-------------------------------------------------------------------------------------------------
|
|
typedef enum
|
|
{
|
|
E_MSPI0,
|
|
E_MSPI1,
|
|
E_MSPI_MAX,
|
|
}MSPI_CH;
|
|
|
|
|
|
typedef enum
|
|
{
|
|
E_MSPI_BIT_MSB_FIRST,
|
|
E_MSPI_BIT_LSB_FIRST,
|
|
}MSPI_BitSeq_e;
|
|
|
|
typedef enum _HAL_CLK_Config
|
|
{
|
|
E_MSPI_POL,
|
|
E_MSPI_PHA,
|
|
E_MSPI_CLK
|
|
}eCLK_config;
|
|
|
|
typedef enum _HAL_DC_Config
|
|
{
|
|
E_MSPI_TRSTART,
|
|
E_MSPI_TREND,
|
|
E_MSPI_TB,
|
|
E_MSPI_TRW
|
|
}eDC_config;
|
|
|
|
typedef struct
|
|
{
|
|
u32 u32Clock;
|
|
u8 u8Clock;
|
|
bool BClkPolarity;
|
|
bool BClkPhase;
|
|
u32 u32MAXClk;
|
|
} MSPI_CLKConfig;
|
|
|
|
|
|
typedef struct
|
|
{
|
|
u8 u8ClkSpi_cfg;
|
|
u8 u8ClkSpi_DIV;
|
|
u32 u32ClkSpi;
|
|
}ST_DRV_MSPI_CLK;
|
|
|
|
typedef enum
|
|
{
|
|
E_MSPI_DBGLV_NONE, //disable all the debug message
|
|
E_MSPI_DBGLV_INFO, //information
|
|
E_MSPI_DBGLV_NOTICE, //normal but significant condition
|
|
E_MSPI_DBGLV_WARNING, //warning conditions
|
|
E_MSPI_DBGLV_ERR, //error conditions
|
|
E_MSPI_DBGLV_CRIT, //critical conditions
|
|
E_MSPI_DBGLV_ALERT, //action must be taken immediately
|
|
E_MSPI_DBGLV_EMERG, //system is unusable
|
|
E_MSPI_DBGLV_DEBUG, //debug-level messages
|
|
} MSPI_DbgLv;
|
|
|
|
typedef enum _MSPI_ERRORNOn {
|
|
E_MSPI_OK = 0
|
|
,E_MSPI_INIT_FLOW_ERROR =1
|
|
,E_MSPI_DCCONFIG_ERROR =2
|
|
,E_MSPI_CLKCONFIG_ERROR =4
|
|
,E_MSPI_FRAMECONFIG_ERROR =8
|
|
,E_MSPI_OPERATION_ERROR = 0x10
|
|
,E_MSPI_PARAM_OVERFLOW = 0x20
|
|
,E_MSPI_MMIO_ERROR = 0x40
|
|
,E_MSPI_HW_NOT_SUPPORT = 0x80
|
|
,E_MSPI_NULL
|
|
} MSPI_ErrorNo;
|
|
|
|
typedef struct
|
|
{
|
|
MSPI_CH eCurrentCH;
|
|
char *VirtMspBaseAddr;
|
|
char *VirtClkBaseAddr;
|
|
char *VirtChiptopBaseAddr;
|
|
char *VirtMovdmaBaseAddr;
|
|
} MSPI_BaseAddr_st;
|
|
|
|
static MSPI_BaseAddr_st _hal_msp = {
|
|
.eCurrentCH = E_MSPI0,
|
|
//.VirtMspBaseAddr = BASE_REG_MSPI0_ADDR,
|
|
//.VirtClkBaseAddr = BASE_REG_CLK_ADDR,
|
|
//.VirtChiptopBaseAddr = BASE_REG_CHIPTOP_ADDR,
|
|
};
|
|
|
|
typedef enum {
|
|
E_MSPI_MODE0, //CPOL = 0,CPHA =0
|
|
E_MSPI_MODE1, //CPOL = 0,CPHA =1
|
|
E_MSPI_MODE2, //CPOL = 1,CPHA =0
|
|
E_MSPI_MODE3, //CPOL = 1,CPHA =1
|
|
E_MSPI_MODE_MAX,
|
|
} MSPI_Mode_Config_e;
|
|
|
|
typedef struct
|
|
{
|
|
u8 u8TrStart; //time from trigger to first SPI clock
|
|
u8 u8TrEnd; //time from last SPI clock to transferred done
|
|
u8 u8TB; //time between byte to byte transfer
|
|
u8 u8TRW; //time between last write and first read
|
|
} MSPI_DCConfig;
|
|
|
|
typedef struct
|
|
{
|
|
u8 u8WBitConfig[8]; //bits will be transferred in write buffer
|
|
u8 u8RBitConfig[8]; //bits Will be transferred in read buffer
|
|
} MSPI_FrameConfig;
|
|
|
|
|
|
#define MSTAR_SPI_TIMEOUT_MS 30000
|
|
#define MSTAR_SPI_MODE_BITS (SPI_CPOL | SPI_CPHA /*| SPI_CS_HIGH | SPI_NO_CS | SPI_LSB_FIRST*/)
|
|
|
|
#define DRV_NAME "spi"
|
|
struct mstar_spi {
|
|
void __iomem *regs;
|
|
struct clk *clk;
|
|
int irq;
|
|
int use_dma;
|
|
int xfer_w_dma;
|
|
struct completion done;
|
|
const u8 *tx_buf;
|
|
u8 *rx_buf;
|
|
int len;
|
|
int wsize;
|
|
char *VirtMspBaseAddr;
|
|
char *VirtClkBaseAddr;
|
|
char *VirtChiptopBaseAddr;
|
|
char *VirtMovdmaBaseAddr;
|
|
char u8channel;
|
|
u32 u32spi_mode;
|
|
u8 bits_per_word;
|
|
};
|
|
|
|
static struct spi_board_info mstar_info = {
|
|
.modalias = "spidev",
|
|
};
|
|
|
|
static void _HAL_MSPI_CheckandSetBaseAddr(MSPI_CH eChannel)
|
|
{
|
|
|
|
#if 0
|
|
if(eChannel == _hal_msp.eCurrentCH)
|
|
{
|
|
return;
|
|
} else if(eChannel == E_MSPI0)
|
|
{
|
|
_hal_msp.eCurrentCH = E_MSPI0;
|
|
_hal_msp.VirtMspBaseAddr = BASE_REG_MSPI0_ADDR;
|
|
_hal_msp.VirtClkBaseAddr = BASE_REG_CLK_ADDR;
|
|
_hal_msp.VirtChiptopBaseAddr = BASE_REG_CHIPTOP_ADDR,
|
|
printk(KERN_ERR"[Lwc Debug] Set mspi0 base address : %x\n",_hal_msp.VirtMspBaseAddr);
|
|
printk(KERN_ERR"[Lwc Debug] Set clk base address : %x\n",_hal_msp.VirtClkBaseAddr);
|
|
} else if(eChannel == E_MSPI1)
|
|
{
|
|
_hal_msp.eCurrentCH = E_MSPI1;
|
|
_hal_msp.VirtMspBaseAddr = BASE_REG_MSPI1_ADDR;
|
|
_hal_msp.VirtClkBaseAddr = BASE_REG_CLK_ADDR;
|
|
_hal_msp.VirtChiptopBaseAddr = BASE_REG_CHIPTOP_ADDR,
|
|
printk(KERN_ERR"[Lwc Debug] Set mspi1 base address : %x\n",_hal_msp.VirtMspBaseAddr);
|
|
printk(KERN_ERR"[Lwc Debug] Set clk base address : %x\n",_hal_msp.VirtClkBaseAddr);
|
|
} else
|
|
{
|
|
//DEBUG_MSPI(E_MSPI_DBGLV_ERR,printk("[Mspi Error]FUN:%s MSPI Channel is out of range!\n",__FUNCTION__));
|
|
printk("[Mspi Error]FUN: MSPI Channel is out of range!\n");
|
|
return ;
|
|
}
|
|
|
|
#endif
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
/// Description : Reset Frame register setting of MSPI
|
|
/// @param NONE
|
|
/// @return TRUE : reset complete
|
|
//------------------------------------------------------------------------------
|
|
BOOL HAL_MSPI_Reset_FrameConfig(struct mstar_spi *bs,MSPI_CH eChannel)
|
|
{
|
|
mutex_lock(&hal_mspi_lock);
|
|
_HAL_MSPI_CheckandSetBaseAddr( eChannel);
|
|
// Frame reset
|
|
MSPI_WRITE(MSPI_FRAME_WBIT_OFFSET, 0xFFF);
|
|
MSPI_WRITE(MSPI_FRAME_WBIT_OFFSET+2, 0xFFF);
|
|
MSPI_WRITE(MSPI_FRAME_RBIT_OFFSET, 0xFFF);
|
|
MSPI_WRITE(MSPI_FRAME_RBIT_OFFSET+2, 0xFFF);
|
|
mutex_unlock(&hal_mspi_lock);
|
|
return TRUE;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/// Description : MSPI interrupt enable
|
|
/// @param bEnable \b OUT: enable or disable mspi interrupt
|
|
/// @return void:
|
|
//------------------------------------------------------------------------------
|
|
void HAL_MSPI_IntEnable(struct mstar_spi *bs,MSPI_CH eChannel,bool bEnable)
|
|
{
|
|
mutex_lock(&hal_mspi_lock);
|
|
_HAL_MSPI_CheckandSetBaseAddr(eChannel);
|
|
|
|
if(bEnable) {
|
|
MSPI_WRITE(MSPI_CTRL_OFFSET,MSPI_READ(MSPI_CTRL_OFFSET)|MSPI_INT_ENABLE);
|
|
} else {
|
|
MSPI_WRITE(MSPI_CTRL_OFFSET,MSPI_READ(MSPI_CTRL_OFFSET)&(~MSPI_INT_ENABLE));
|
|
}
|
|
mutex_unlock(&hal_mspi_lock);
|
|
}
|
|
|
|
#if defined(CONFIG_MS_PADMUX)
|
|
static int _MSPI_IsPadSet(MSPI_CH eChannel)
|
|
{
|
|
// important: need to modify if more MDRV_PUSE_SPI? defined
|
|
if (eChannel == E_MSPI0 && PAD_UNKNOWN != mdrv_padmux_getpad(MDRV_PUSE_SPI0_CK) )
|
|
{
|
|
//printk("SPI: %d pad set by padmux driver!!\n", eChannel);
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
#endif
|
|
|
|
void HAL_MSPI_Init(struct mstar_spi *bs,MSPI_CH eChannel,u8 u8Mode)
|
|
{
|
|
u16 TempData;
|
|
//init MSP
|
|
//DEBUG_MSPI(E_MSPI_DBGLV_INFO,printk("HAL_MSPI_Init\n"));
|
|
mspi_dbgmsg("HAL_MSPI_Init : Channel=%d spi mode=%d\n",eChannel,u8Mode);
|
|
mutex_init(&hal_mspi_lock);
|
|
if((eChannel > E_MSPI1) || (u8Mode < 1))
|
|
{
|
|
return;
|
|
}
|
|
else if((eChannel == E_MSPI0) && (u8Mode > 6))
|
|
{
|
|
return;
|
|
}
|
|
#if SUPPORT_SPI_1
|
|
else if((eChannel == E_MSPI1) && (u8Mode > 6))
|
|
{
|
|
return;
|
|
}
|
|
#endif
|
|
mutex_lock(&hal_mspi_lock);
|
|
_HAL_MSPI_CheckandSetBaseAddr(eChannel);
|
|
|
|
MSPI_WRITE(MSPI_CTRL_OFFSET,MSPI_READ(MSPI_CTRL_OFFSET)|(MSPI_RESET|MSPI_ENABLE));
|
|
|
|
if(eChannel == E_MSPI0)
|
|
{
|
|
// CLK SETTING
|
|
TempData = CLK_READ(MSPI0_CLK_CFG);
|
|
TempData &= ~(MSPI0_CLK_MASK);
|
|
TempData |= MSPI0_CLK_108M;
|
|
CLK_WRITE(MSPI0_CLK_CFG, TempData);
|
|
|
|
#if defined(CONFIG_MS_PADMUX)
|
|
if (0 == mdrv_padmux_active() ||
|
|
FALSE == _MSPI_IsPadSet(E_MSPI0) )
|
|
#endif
|
|
{
|
|
pr_info("SPI: %d pad set by SPI driver!!\n", eChannel);
|
|
//select mspi mode
|
|
TempData = CHIPTOP_READ(MSPI0_MODE);
|
|
TempData &= ~(MSPI0_MODE_MASK);
|
|
TempData |= u8Mode;
|
|
CHIPTOP_WRITE(MSPI0_MODE,TempData);
|
|
|
|
//Disable jtag mode // IO PAD conflict turn off jtag
|
|
TempData = CHIPTOP_READ(EJTAG_MODE);
|
|
if((u8Mode == 4 && TempData == EJTAG_MODE_1) ||
|
|
(u8Mode == 3 && TempData == EJTAG_MODE_3) ){
|
|
TempData &= ~(EJTAG_MODE_MASK);
|
|
CHIPTOP_WRITE(EJTAG_MODE,TempData);
|
|
}
|
|
}
|
|
}
|
|
#if SUPPORT_SPI_1
|
|
else if (eChannel == E_MSPI1)
|
|
{
|
|
// CLK SETTING
|
|
TempData = CLK_READ(MSPI1_CLK_CFG);
|
|
TempData &= ~(MSPI1_CLK_MASK);
|
|
TempData |= MSPI1_CLK_108M;
|
|
CLK_WRITE(MSPI1_CLK_CFG, TempData);
|
|
|
|
#if defined(CONFIG_MS_PADMUX)
|
|
if (0 == mdrv_padmux_active() ||
|
|
FALSE == _MSPI_IsPadSet(E_MSPI1) )
|
|
#endif
|
|
{
|
|
//select mspi mode
|
|
TempData = CHIPTOP_READ(MSPI1_MODE);
|
|
TempData &= ~(MSPI1_MODE_MASK);
|
|
TempData |= (u8Mode << 4);
|
|
CHIPTOP_WRITE(MSPI1_MODE,TempData);
|
|
}
|
|
}
|
|
#endif
|
|
mutex_unlock(&hal_mspi_lock);
|
|
return;
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
/// Description : config spi transfer timing
|
|
/// @param ptDCConfig \b OUT struct pointer of bits of buffer tranferred to slave config
|
|
/// @return NONE
|
|
//------------------------------------------------------------------------------
|
|
void HAL_MSPI_SetDcTiming (struct mstar_spi *bs,MSPI_CH eChannel, eDC_config eDCField, U8 u8DCtiming)
|
|
{
|
|
U16 u16TempBuf = 0;
|
|
mutex_lock(&hal_mspi_lock);
|
|
_HAL_MSPI_CheckandSetBaseAddr(eChannel);
|
|
switch(eDCField) {
|
|
case E_MSPI_TRSTART:
|
|
u16TempBuf = MSPI_READ(MSPI_DC_TR_START_OFFSET);
|
|
u16TempBuf &= (~MSPI_DC_MASK);
|
|
u16TempBuf |= u8DCtiming;
|
|
MSPI_WRITE(MSPI_DC_TR_START_OFFSET, u16TempBuf);
|
|
break;
|
|
case E_MSPI_TREND:
|
|
u16TempBuf = MSPI_READ(MSPI_DC_TR_END_OFFSET);
|
|
u16TempBuf &= MSPI_DC_MASK;
|
|
u16TempBuf |= u8DCtiming << MSPI_DC_BIT_OFFSET;
|
|
MSPI_WRITE(MSPI_DC_TR_END_OFFSET, u16TempBuf);
|
|
break;
|
|
case E_MSPI_TB:
|
|
u16TempBuf = MSPI_READ(MSPI_DC_TB_OFFSET);
|
|
u16TempBuf &= (~MSPI_DC_MASK);
|
|
u16TempBuf |= u8DCtiming;
|
|
MSPI_WRITE(MSPI_DC_TB_OFFSET, u16TempBuf);
|
|
break;
|
|
case E_MSPI_TRW:
|
|
u16TempBuf = MSPI_READ(MSPI_DC_TRW_OFFSET);
|
|
u16TempBuf &= MSPI_DC_MASK;
|
|
u16TempBuf |= u8DCtiming << MSPI_DC_BIT_OFFSET;
|
|
MSPI_WRITE(MSPI_DC_TRW_OFFSET, u16TempBuf);
|
|
break;
|
|
}
|
|
|
|
mutex_unlock(&hal_mspi_lock);
|
|
}
|
|
|
|
static void _HAL_MSPI_RWBUFSize(struct mstar_spi *bs,BOOL Direct, U8 Size)
|
|
{
|
|
U16 u16Data = 0;
|
|
u16Data = MSPI_READ(MSPI_RBF_SIZE_OFFSET);
|
|
//printk("===RWBUFSize:%d\n",Size);
|
|
if(Direct == MSPI_READ_INDEX)
|
|
{
|
|
u16Data &= MSPI_RWSIZE_MASK;
|
|
u16Data |= Size << MSPI_RSIZE_BIT_OFFSET;
|
|
}
|
|
else
|
|
{
|
|
u16Data &= ~MSPI_RWSIZE_MASK;
|
|
u16Data |= Size;
|
|
}
|
|
MSPI_WRITE(MSPI_RBF_SIZE_OFFSET, u16Data);
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
/// Description : check MSPI operation complete
|
|
/// @return TRUE : operation complete
|
|
/// @return FAIL : failed timeout
|
|
//------------------------------------------------------------------------------
|
|
static U16 _HAL_MSPI_CheckDone(struct mstar_spi *bs)
|
|
{
|
|
/*
|
|
U16 uCheckDoneCnt = 0;
|
|
U16 uDoneFlag = 0;
|
|
while(uCheckDoneCnt < MAX_CHECK_CNT) {
|
|
uDoneFlag = MSPI_READ(MSPI_DONE_OFFSET);
|
|
if(uDoneFlag & MSPI_DONE_FLAG) {
|
|
printk("Done flag success!!!!!!!!!!!!!!!!!!!!!!!!\n");
|
|
return TRUE;
|
|
}
|
|
// printk("...");
|
|
uCheckDoneCnt++;
|
|
}
|
|
//DEBUG_MSPI(E_MSPI_DBGLV_ERR,printk("ERROR:MSPI Operation Timeout!!!!!\n"));
|
|
printk("ERROR:MSPI Operation asasTimeout!!!!!\n");
|
|
return FALSE;
|
|
*/
|
|
|
|
return MSPI_READ(MSPI_DONE_OFFSET);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/// Description : SPI chip select enable and disable
|
|
/// @param Enable \b OUT: enable or disable chip select
|
|
//------------------------------------------------------------------------------
|
|
static void _HAL_MSPI_ChipSelect(struct mstar_spi *bs,BOOL Enable ,U8 eSelect)
|
|
{
|
|
U16 regdata = 0;
|
|
U8 bitmask = 0;
|
|
regdata = MSPI_READ(MSPI_CHIP_SELECT_OFFSET);
|
|
if(Enable) {
|
|
bitmask = ~(1 << eSelect);
|
|
regdata &= bitmask;
|
|
} else {
|
|
bitmask = (1 << eSelect);
|
|
regdata |= bitmask;
|
|
}
|
|
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, regdata);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/// Description : Trigger MSPI operation
|
|
/// @return TRUE : operation success
|
|
/// @return FALSE : operation timeout
|
|
//------------------------------------------------------------------------------
|
|
#ifdef _EN_MSPI_INTC_
|
|
BOOL _HAL_MSPI_Trigger(struct mstar_spi *bs)
|
|
{
|
|
unsigned int timeout;
|
|
// trigger operation
|
|
reinit_completion(&bs->done);
|
|
MSPI_WRITE(MSPI_TRIGGER_OFFSET,MSPI_TRIGGER);
|
|
|
|
|
|
timeout = wait_for_completion_timeout(&bs->done,
|
|
msecs_to_jiffies(MSTAR_SPI_TIMEOUT_MS));
|
|
|
|
MSPI_WRITE(MSPI_RBF_SIZE_OFFSET,0x0);
|
|
|
|
if (!timeout) {
|
|
mspi_dbgmsg("timeout\n");
|
|
//goto out;
|
|
}
|
|
else {
|
|
if(bs->xfer_w_dma){ // clear MOVDMA finish status
|
|
u16 intsrc = MOVDMA_READ(MOV_DMA_IRQ_FINAL_STATUS);
|
|
MOVDMA_WRITE(DMA_MOVE0_IRQ_CLR, intsrc);
|
|
}
|
|
}
|
|
|
|
// check operation complete
|
|
// if(!_HAL_MSPI_CheckDone()) {
|
|
// return FALSE;
|
|
// }
|
|
// clear done flag
|
|
// _HAL_MSPI_ClearDone();
|
|
// reset read/write buffer size
|
|
// MSPI_WRITE(MSPI_RBF_SIZE_OFFSET,0x0);
|
|
return TRUE;
|
|
}
|
|
#else
|
|
#define HW_MSPI_WAIT_TIMEOUT (30000)
|
|
BOOL _HAL_MSPI_Trigger(struct mstar_spi *bs)
|
|
{
|
|
U16 volatile time_remain = HW_MSPI_WAIT_TIMEOUT;
|
|
// trigger operation
|
|
MSPI_WRITE(MSPI_TRIGGER_OFFSET,MSPI_TRIGGER);
|
|
|
|
|
|
while (time_remain--) {
|
|
|
|
if (_HAL_MSPI_CheckDone(bs) == 1) { //done
|
|
if(bs->xfer_w_dma){ // clear MOVDMA finish status
|
|
u16 intsrc = MOVDMA_READ(MOV_DMA_IRQ_FINAL_STATUS);
|
|
MOVDMA_WRITE(DMA_MOVE0_IRQ_CLR, intsrc);
|
|
}
|
|
_HAL_MSPI_ClearDone(); // for debug
|
|
mspi_dbgmsg("<<<<<<<<<<<<<<<<<<< SPI_Done >>>>>>>>>>>>>>>>>\n");
|
|
break;
|
|
}
|
|
}
|
|
|
|
MSPI_WRITE(MSPI_RBF_SIZE_OFFSET,0x0);
|
|
|
|
if (!time_remain) {
|
|
mspi_dbgmsg("timeout\n");
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
#endif
|
|
//-------------------------------------------------------------------------------------------------
|
|
/// Description : read data from MSPI
|
|
/// @param pData \b IN :pointer to receive data from MSPI read buffer
|
|
/// @param u16Size \ b OTU : read data size
|
|
/// @return TRUE : read data success
|
|
/// @return FALSE : read data fail
|
|
//-------------------------------------------------------------------------------------------------
|
|
BOOL HAL_MSPI_Read(struct mstar_spi *bs, MSPI_CH eChannel, U8 *pData, U16 u16Size)
|
|
{
|
|
U8 u8Index = 0;
|
|
U16 u16TempBuf = 0;
|
|
U16 i =0, j = 0;
|
|
U8 shift;
|
|
U8 isMsbBitMode = (bs->bits_per_word % 8) && !(bs->u32spi_mode & SPI_LSB_FIRST);
|
|
|
|
mutex_lock(&hal_mspi_lock);
|
|
_HAL_MSPI_CheckandSetBaseAddr( eChannel);
|
|
for(i = 0; i < u16Size; i+= MAX_READ_BUF_SIZE) {
|
|
u16TempBuf = u16Size - i;
|
|
if(u16TempBuf > MAX_READ_BUF_SIZE) {
|
|
j = MAX_READ_BUF_SIZE;
|
|
} else {
|
|
j = u16TempBuf;
|
|
}
|
|
_HAL_MSPI_RWBUFSize(bs,MSPI_READ_INDEX, j);
|
|
|
|
_HAL_MSPI_Trigger(bs);
|
|
|
|
for(u8Index = 0; u8Index < j; u8Index++) {
|
|
|
|
if(u8Index & 1) {
|
|
u16TempBuf = MSPI_READ((MSPI_READ_BUF_OFFSET + (u8Index >> 1)));
|
|
//DEBUG_MSPI(E_MSPI_DBGLV_DEBUG,printk("read Buf data %x index %d\n",u16TempBuf, u8Index));
|
|
if (isMsbBitMode)
|
|
{
|
|
if (bs->bits_per_word < 8)
|
|
{
|
|
shift = 8 - bs->bits_per_word;
|
|
pData[u8Index] = u16TempBuf >> (8 + shift);
|
|
pData[u8Index-1] = (u16TempBuf & 0xFF) >> shift;
|
|
}
|
|
else //bits_per_word=9~15
|
|
{
|
|
shift = 16 - bs->bits_per_word;
|
|
pData[u8Index] = u16TempBuf >> 8;
|
|
pData[u8Index-1] = (u16TempBuf & 0xFF) >> shift;
|
|
}
|
|
}
|
|
else {
|
|
pData[u8Index] = u16TempBuf >> 8;
|
|
pData[u8Index-1] = u16TempBuf & 0xFF;
|
|
}
|
|
} else if(u8Index == (j -1)) {
|
|
u16TempBuf = MSPI_READ((MSPI_READ_BUF_OFFSET + (u8Index >> 1)));
|
|
//DEBUG_MSPI(E_MSPI_DBGLV_DEBUG,printk("read Buf data %x index %d\n",u16TempBuf, u8Index));
|
|
if (isMsbBitMode) {
|
|
pData[u8Index] = (u16TempBuf & 0xFF) >> (8 - bs->bits_per_word);
|
|
}
|
|
else {
|
|
pData[u8Index] = u16TempBuf & 0xFF;
|
|
}
|
|
}
|
|
|
|
//printk("******************* read Buf data %x index %d\n",u16TempBuf, u8Index);
|
|
}
|
|
pData+= j;
|
|
}
|
|
|
|
mutex_unlock(&hal_mspi_lock);
|
|
return TRUE;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/// Description : read data from MSPI
|
|
/// @param pData \b OUT :pointer to write data to MSPI write buffer
|
|
/// @param u16Size \ b OTU : write data size
|
|
/// @return TRUE : write data success
|
|
/// @return FALSE : wirte data fail
|
|
//------------------------------------------------------------------------------
|
|
BOOL HAL_MSPI_Write(struct mstar_spi *bs, MSPI_CH eChannel, U8 *pData, U16 u16Size)
|
|
{
|
|
U8 u8Index = 0, u8TempBuf;
|
|
U16 u16TempBuf = 0;
|
|
U8 shift;
|
|
U8 isMsbBitMode = (bs->bits_per_word % 8) && !(bs->u32spi_mode & SPI_LSB_FIRST);
|
|
|
|
mutex_lock(&hal_mspi_lock);
|
|
_HAL_MSPI_CheckandSetBaseAddr( eChannel);
|
|
|
|
// bit mode: to send 1 0000 0101
|
|
// we get data[0]=0x01,data[1]=0x05 from users
|
|
// We must fill wbuf[0]=0x80,wbuf[1]=0x05 for HW MSB bit mode
|
|
for(u8Index = 0; u8Index < u16Size; u8Index++) {
|
|
if(u8Index & 1) {
|
|
if (isMsbBitMode) {
|
|
if (bs->bits_per_word < 8)
|
|
{
|
|
shift = 8 - bs->bits_per_word;
|
|
u16TempBuf = (pData[u8Index] << (8+shift)) | (pData[u8Index-1] << shift);
|
|
}
|
|
else //bits_per_word=9~15
|
|
{
|
|
shift = 16 - bs->bits_per_word;
|
|
u16TempBuf = (pData[u8Index] << 8) | (pData[u8Index-1] << shift);
|
|
}
|
|
}
|
|
else {
|
|
u16TempBuf = (pData[u8Index] << 8) | pData[u8Index-1];
|
|
}
|
|
//DEBUG_MSPI(E_MSPI_DBGLV_DEBUG,printk("write Buf data %x index %d\n",u16TempBuf, u8Index));
|
|
MSPI_WRITE((MSPI_WRITE_BUF_OFFSET + (u8Index >> 1)),u16TempBuf);
|
|
} else if(u8Index == (u16Size -1)) {
|
|
if (isMsbBitMode) {
|
|
u8TempBuf = pData[u8Index] << (8 - bs->bits_per_word);
|
|
}
|
|
else {
|
|
u8TempBuf = pData[u8Index];
|
|
}
|
|
//DEBUG_MSPI(E_MSPI_DBGLV_DEBUG,printk("write Buf data %x index %d\n",u8TempBuf, u8Index));
|
|
MSPI_WRITE((MSPI_WRITE_BUF_OFFSET + (u8Index >> 1)),u8TempBuf);
|
|
}
|
|
}
|
|
|
|
_HAL_MSPI_RWBUFSize(bs,MSPI_WRITE_INDEX, u16Size);
|
|
_HAL_MSPI_Trigger(bs);
|
|
// set write data size
|
|
mutex_unlock(&hal_mspi_lock);
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL HAL_MSPI_FullDuplex(struct mstar_spi *bs , MSPI_CH eChannel, U8 *txdata, U8 *rxdata, U16 u16size)
|
|
{
|
|
U16 fullDeplux_rd_cnt = 0;
|
|
U16 *u16val = (U16*)rxdata;
|
|
U16 i = 0;
|
|
BOOL bRet = FALSE;
|
|
|
|
/* tx */
|
|
bRet = HAL_MSPI_Write(bs, eChannel, txdata, u16size);
|
|
|
|
/*read duplux buffer*/
|
|
fullDeplux_rd_cnt = MSPI_READ(MSPI_FULL_DEPLUX_RD_CNT)&0xFF;
|
|
|
|
for(i = 0; i < fullDeplux_rd_cnt/2; i++)
|
|
{
|
|
u16val[i] = MSPI_READ(MSPI_FULL_DEPLUX_RD00+i);
|
|
}
|
|
|
|
if(fullDeplux_rd_cnt%2)
|
|
{
|
|
rxdata[fullDeplux_rd_cnt - 1] = ((MSPI_READ(MSPI_FULL_DEPLUX_RD00 + fullDeplux_rd_cnt/2)) &0xFF);
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/// Description : Reset CLK register setting of MSPI
|
|
/// @param NONE
|
|
/// @return TRUE : reset complete
|
|
//------------------------------------------------------------------------------
|
|
BOOL HAL_MSPI_Reset_CLKConfig(struct mstar_spi *bs,MSPI_CH eChannel)
|
|
{
|
|
U16 Tempbuf;
|
|
mutex_lock(&hal_mspi_lock);
|
|
_HAL_MSPI_CheckandSetBaseAddr( eChannel);
|
|
//reset clock
|
|
Tempbuf = MSPI_READ(MSPI_CTRL_OFFSET);
|
|
Tempbuf &= 0x3F;
|
|
MSPI_WRITE(MSPI_CTRL_OFFSET, Tempbuf);
|
|
mutex_unlock(&hal_mspi_lock);
|
|
return TRUE;
|
|
}
|
|
|
|
U8 HAL_MSPI_DCConfigMax(eDC_config eDCField)
|
|
{
|
|
switch(eDCField)
|
|
{
|
|
case E_MSPI_TRSTART:
|
|
return MSPI_DC_TRSTART_MAX;
|
|
case E_MSPI_TREND:
|
|
return MSPI_DC_TREND_MAX;
|
|
case E_MSPI_TB:
|
|
return MSPI_DC_TB_MAX;
|
|
case E_MSPI_TRW:
|
|
return MSPI_DC_TRW_MAX;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/// Description : Set TrStart timing of DC config
|
|
/// @return E_MSPI_OK :
|
|
/// @return >1 : failed to set TrStart timing
|
|
//------------------------------------------------------------------------------
|
|
static U8 _MDrv_DC_TrStartSetting(struct mstar_spi *bs,U8 u8Channel,U8 TrStart)
|
|
{
|
|
U8 u8TrStartMax;
|
|
U8 errnum = E_MSPI_OK;
|
|
|
|
u8TrStartMax = HAL_MSPI_DCConfigMax(E_MSPI_TRSTART);
|
|
if(TrStart > u8TrStartMax)
|
|
errnum = E_MSPI_PARAM_OVERFLOW;
|
|
else
|
|
HAL_MSPI_SetDcTiming(bs,(MSPI_CH)u8Channel,E_MSPI_TRSTART ,TrStart);
|
|
return errnum;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/// Description : Reset DC register setting of MSPI
|
|
/// @param NONE
|
|
/// @return TRUE : reset complete
|
|
//------------------------------------------------------------------------------
|
|
BOOL HAL_MSPI_Reset_DCConfig(struct mstar_spi *bs,MSPI_CH eChannel)
|
|
{
|
|
mutex_lock(&hal_mspi_lock);
|
|
_HAL_MSPI_CheckandSetBaseAddr( eChannel);
|
|
//DC reset
|
|
MSPI_WRITE(MSPI_DC_TR_START_OFFSET, 0x00);
|
|
MSPI_WRITE(MSPI_DC_TB_OFFSET, 0x00);
|
|
mutex_unlock(&hal_mspi_lock);
|
|
return TRUE;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/// Description : Set MSPI chip select
|
|
/// @param u8CS \u8 OUT: MSPI chip select
|
|
/// @return void:
|
|
//------------------------------------------------------------------------------
|
|
void HAL_MSPI_SetChipSelect(struct mstar_spi *bs,MSPI_CH eChannel, BOOL Enable, U8 u8CS)
|
|
{
|
|
mutex_lock(&hal_mspi_lock);
|
|
_HAL_MSPI_CheckandSetBaseAddr( eChannel);
|
|
_HAL_MSPI_ChipSelect(bs, Enable, u8CS);
|
|
mutex_unlock(&hal_mspi_lock);
|
|
}
|
|
// add to sync code from utopia for localdimming to set clk
|
|
void MDrv_MSPI_ChipSelect(struct mstar_spi *bs,U8 u8Channel, BOOL Enable, U8 u8CS)
|
|
{
|
|
HAL_MSPI_SetChipSelect(bs,(MSPI_CH)u8Channel,Enable,u8CS);
|
|
return;
|
|
}
|
|
|
|
U32 HAL_MSPI_SelectCLK(struct mstar_spi *bs,U8 u8Channel) //Enable DMA CLK
|
|
{
|
|
u16 TempData;
|
|
|
|
TempData = CLK_READ(MSPI_CLK_CFG);
|
|
if(u8Channel == E_MSPI0)//mspi0
|
|
{
|
|
// CLK SETTING
|
|
TempData &= ~(MSPI_CLK_MASK);
|
|
TempData |= MSPI_SELECT_0;
|
|
}
|
|
else if(u8Channel == E_MSPI1)//mspi1
|
|
{
|
|
// CLK SETTING
|
|
TempData &= ~(MSPI_CLK_MASK);
|
|
TempData |= MSPI_SELECT_1;
|
|
}
|
|
CLK_WRITE(MSPI_CLK_CFG, TempData);
|
|
|
|
return 0;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------
|
|
/// Description : read data from MSPI
|
|
/// @param pData \b IN :pointer to receive data from MSPI read buffer
|
|
/// @param u16Size \ b OTU : read data size
|
|
/// @return the errorno of operation
|
|
//-------------------------------------------------------------------------------------------------
|
|
U8 MDrv_MSPI_Read(struct mstar_spi *bs, U8 u8Channel, U8 *pData, U16 u16Size)
|
|
{
|
|
//MSPI_ErrorNo errorno = E_MSPI_OK;
|
|
|
|
U8 u8Index = 0;
|
|
U8 u8TempFrameCnt=0;
|
|
U8 U8TempLastFrameCnt=0;
|
|
int ret = 0;
|
|
if(pData == NULL) {
|
|
return E_MSPI_NULL;
|
|
}
|
|
u8TempFrameCnt = u16Size/MAX_WRITE_BUF_SIZE; //Cut data to frame by max frame size
|
|
U8TempLastFrameCnt = u16Size%MAX_WRITE_BUF_SIZE; //Last data less than a MAX_WRITE_BUF_SIZE fame
|
|
for (u8Index = 0; u8Index < u8TempFrameCnt; u8Index++) {
|
|
ret = HAL_MSPI_Read(bs,(MSPI_CH)u8Channel,pData+u8Index*MAX_WRITE_BUF_SIZE,MAX_WRITE_BUF_SIZE);
|
|
if (!ret) {
|
|
return E_MSPI_OPERATION_ERROR;
|
|
}
|
|
}
|
|
if(U8TempLastFrameCnt) {
|
|
ret = HAL_MSPI_Read(bs,(MSPI_CH)u8Channel,pData+u8TempFrameCnt*MAX_WRITE_BUF_SIZE,U8TempLastFrameCnt);
|
|
}
|
|
if (!ret) {
|
|
return E_MSPI_OPERATION_ERROR;
|
|
}
|
|
return E_MSPI_OK;
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
/// Description : write data from MSPI
|
|
/// @param pData \b OUT :pointer to write data to MSPI write buffer
|
|
/// @param u16Size \ b OTU : write data size
|
|
/// @return the errorno of operation
|
|
//------------------------------------------------------------------------------
|
|
U8 MDrv_MSPI_Write(struct mstar_spi *bs,U8 u8Channel, U8 *pData, U16 u16Size)
|
|
{
|
|
U8 u8Index = 0;
|
|
U8 u8TempFrameCnt=0;
|
|
U8 U8TempLastFrameCnt=0;
|
|
BOOL ret = false;
|
|
u8TempFrameCnt = u16Size/MAX_WRITE_BUF_SIZE; //Cut data to frame by max frame size
|
|
U8TempLastFrameCnt = u16Size%MAX_WRITE_BUF_SIZE; //Last data less than a MAX_WRITE_BUF_SIZE fame
|
|
for (u8Index = 0; u8Index < u8TempFrameCnt; u8Index++)
|
|
{
|
|
ret = HAL_MSPI_Write(bs, (MSPI_CH)u8Channel,pData+u8Index*MAX_WRITE_BUF_SIZE,MAX_WRITE_BUF_SIZE);
|
|
if (!ret) {
|
|
return E_MSPI_OPERATION_ERROR;
|
|
}
|
|
}
|
|
|
|
if(U8TempLastFrameCnt)
|
|
{
|
|
ret = HAL_MSPI_Write(bs, (MSPI_CH)u8Channel,pData+u8TempFrameCnt*MAX_WRITE_BUF_SIZE,U8TempLastFrameCnt);
|
|
}
|
|
|
|
if (!ret) {
|
|
return E_MSPI_OPERATION_ERROR;
|
|
}
|
|
return E_MSPI_OK;
|
|
}
|
|
|
|
BOOL MDrv_MSPI_FullDuplex(struct mstar_spi *bs, U8 u8Channel, U8 *txdata, U8 *rxdata, U16 u16size)
|
|
{
|
|
U8 i = 0;
|
|
U8 frmcnt = 0;
|
|
U8 lastfrmsize = 0;
|
|
|
|
frmcnt = u16size/MAX_WRITE_BUF_SIZE;
|
|
lastfrmsize = u16size%MAX_WRITE_BUF_SIZE;
|
|
|
|
for (i = 0; i < frmcnt; i++)
|
|
{
|
|
if(!HAL_MSPI_FullDuplex(bs, (MSPI_CH)u8Channel, txdata + i * MAX_WRITE_BUF_SIZE, rxdata + i * MAX_WRITE_BUF_SIZE, MAX_WRITE_BUF_SIZE))
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
if(!lastfrmsize)
|
|
return TRUE;
|
|
|
|
return HAL_MSPI_FullDuplex(bs, (MSPI_CH)u8Channel, txdata + frmcnt * MAX_WRITE_BUF_SIZE, rxdata + frmcnt * MAX_WRITE_BUF_SIZE, lastfrmsize);
|
|
}
|
|
|
|
|
|
U8 MDrv_MSPI_DMA_Read(struct mstar_spi *bs, U8 u8Channel, U8 *pData, U16 u16Size)
|
|
{
|
|
dma_addr_t data_addr;
|
|
|
|
if(pData == NULL) {
|
|
return E_MSPI_NULL;
|
|
}
|
|
mutex_lock(&hal_mspi_lock);
|
|
|
|
HAL_MSPI_SelectCLK(bs, u8Channel);
|
|
|
|
MOVDMA_WRITE( DMA_RW, DMA_READ); // 1 for dma read from device
|
|
|
|
MSPI_WRITE(MSPI_DMA_ENABLE, 0x01);
|
|
MSPI_WRITE(MSPI_DMA_RW_MODE, MSPI_DMA_READ);
|
|
|
|
MSPI_WRITE(MSPI_DMA_DATA_LENGTH_L, u16Size & 0xFFFF );
|
|
MSPI_WRITE(MSPI_DMA_DATA_LENGTH_H, (u16Size>>16)& 0x00FF); // 24bit
|
|
|
|
MOVDMA_WRITE(MOV_DMA_BYTE_CNT_L, u16Size & 0xFFFF );
|
|
MOVDMA_WRITE(MOV_DMA_BYTE_CNT_H, u16Size>>16 );
|
|
|
|
data_addr=dma_map_single(NULL, pData, u16Size, DMA_TO_DEVICE);
|
|
if(data_addr > SPI_MIU1_BUS_BASE)
|
|
data_addr -= SPI_MIU1_BUS_BASE;
|
|
else
|
|
data_addr -= SPI_MIU0_BUS_BASE;
|
|
|
|
MOVDMA_WRITE(MOV_DMA_DST_ADDR_L, data_addr & 0x0000FFFF );
|
|
MOVDMA_WRITE(MOV_DMA_DST_ADDR_H, data_addr >>16 );
|
|
|
|
MOVDMA_WRITE(0x00,0x01);//dma enable
|
|
_HAL_MSPI_ChipSelect(bs,1,0);//enable chip select for device0 (pulled low)
|
|
_HAL_MSPI_RWBUFSize(bs,MSPI_READ_INDEX, 0); //spi length = 0
|
|
_HAL_MSPI_Trigger(bs);
|
|
_HAL_MSPI_ChipSelect(bs,0,0);//disable chip select for device0 (pulled high)
|
|
|
|
mutex_unlock(&hal_mspi_lock);
|
|
return E_MSPI_OK;
|
|
}
|
|
|
|
U8 MDrv_MSPI_DMA_Write(struct mstar_spi *bs,U8 u8Channel, U8 *pData, U16 u16Size)
|
|
{
|
|
dma_addr_t data_addr;
|
|
mutex_lock(&hal_mspi_lock);
|
|
|
|
//printk("### MDrv_MSPI_DMA_Write\r\n");
|
|
|
|
HAL_MSPI_SelectCLK(bs, u8Channel);
|
|
|
|
MOVDMA_WRITE( DMA_RW, DMA_WRITE );//0 for dma write to device
|
|
MOVDMA_WRITE( DMA_DEVICE_MODE, 0x0001 ); // 1 to enable dma device mode
|
|
MOVDMA_WRITE( DMA_DEVICE_SEL, bs->u8channel); //0 select mspi0 , 1 select mspi1
|
|
|
|
MSPI_WRITE(MSPI_DMA_ENABLE, 0x01);
|
|
MSPI_WRITE(MSPI_DMA_RW_MODE, MSPI_DMA_WRITE);
|
|
|
|
MSPI_WRITE(MSPI_DMA_DATA_LENGTH_L, u16Size & 0xFFFF );
|
|
MSPI_WRITE(MSPI_DMA_DATA_LENGTH_H, u16Size>>16 );
|
|
|
|
MOVDMA_WRITE(MOV_DMA_BYTE_CNT_L, u16Size & 0xFFFF );
|
|
MOVDMA_WRITE(MOV_DMA_BYTE_CNT_H, u16Size>>16 );
|
|
|
|
data_addr=dma_map_single(NULL, pData, u16Size, DMA_FROM_DEVICE);
|
|
if(data_addr > SPI_MIU1_BUS_BASE)
|
|
data_addr -= SPI_MIU1_BUS_BASE;
|
|
else
|
|
data_addr -= SPI_MIU0_BUS_BASE;
|
|
|
|
Chip_Flush_MIU_Pipe();
|
|
|
|
MOVDMA_WRITE(MOV_DMA_SRC_ADDR_L, data_addr & 0x0000FFFF );
|
|
MOVDMA_WRITE(MOV_DMA_SRC_ADDR_H, data_addr >>16);
|
|
|
|
|
|
MOVDMA_WRITE(0x00,0x01);//dma enable
|
|
_HAL_MSPI_ChipSelect(bs,1,0);//enable chip select for device0 (pulled low)
|
|
_HAL_MSPI_RWBUFSize(bs,MSPI_WRITE_INDEX, 0);
|
|
_HAL_MSPI_Trigger(bs);
|
|
_HAL_MSPI_ChipSelect(bs,0,0);//disable chip select for device0 (pulled high)
|
|
|
|
mutex_unlock(&hal_mspi_lock);
|
|
return E_MSPI_OK;
|
|
}
|
|
|
|
|
|
u8 MDrv_MSPI_Init(struct mstar_spi *bs,u8 u8Channel,u8 u8Mode)
|
|
{
|
|
u8 errorno = E_MSPI_OK;
|
|
HAL_MSPI_Init(bs,(MSPI_CH)u8Channel,u8Mode);
|
|
HAL_MSPI_IntEnable(bs,(MSPI_CH)u8Channel,true);
|
|
gbInitFlag = true;
|
|
return errorno;
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
/// Description : Set TrEnd timing of DC config
|
|
/// @return E_MSPI_OK :
|
|
/// @return >1 : failed to set TrEnd timing
|
|
//------------------------------------------------------------------------------
|
|
static U8 _MDrv_DC_TrEndSetting(struct mstar_spi *bs,U8 u8Channel,U8 TrEnd)
|
|
{
|
|
U8 u8TrEndMax;
|
|
U8 errnum = E_MSPI_OK;
|
|
|
|
u8TrEndMax = HAL_MSPI_DCConfigMax(E_MSPI_TREND);
|
|
if(TrEnd > u8TrEndMax)
|
|
errnum = E_MSPI_PARAM_OVERFLOW;
|
|
else
|
|
HAL_MSPI_SetDcTiming(bs,(MSPI_CH)u8Channel,E_MSPI_TREND ,TrEnd);
|
|
return errnum;
|
|
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
/// Description : Set TB timing of DC config
|
|
/// @return E_MSPI_OK :
|
|
/// @return >1 : failed to set TB timing
|
|
//------------------------------------------------------------------------------
|
|
static U8 _MDrv_DC_TBSetting(struct mstar_spi *bs,U8 u8Channel,U8 TB)
|
|
{
|
|
U8 u8TBMax;
|
|
U8 errnum = E_MSPI_OK;
|
|
|
|
u8TBMax = HAL_MSPI_DCConfigMax(E_MSPI_TB);
|
|
if(TB > u8TBMax)
|
|
errnum = E_MSPI_PARAM_OVERFLOW;
|
|
else
|
|
HAL_MSPI_SetDcTiming(bs,(MSPI_CH)u8Channel,E_MSPI_TB ,TB);
|
|
return errnum;
|
|
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
/// Description : Set TRW timing of DC config
|
|
/// @return E_MSPI_OK :
|
|
/// @return >1 : failed to set TRW timging
|
|
//------------------------------------------------------------------------------
|
|
static U8 _MDrv_DC_TRWSetting(struct mstar_spi *bs,U8 u8Channel,U8 TRW)
|
|
{
|
|
U8 u8TRWMax;
|
|
U8 errnum = E_MSPI_OK;
|
|
|
|
u8TRWMax = HAL_MSPI_DCConfigMax(E_MSPI_TRW);
|
|
if(TRW > u8TRWMax)
|
|
errnum = E_MSPI_PARAM_OVERFLOW;
|
|
else
|
|
HAL_MSPI_SetDcTiming(bs,(MSPI_CH)u8Channel,E_MSPI_TRW ,TRW);
|
|
return errnum;
|
|
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
/// Description : config spi transfer timing
|
|
/// @param ptDCConfig \b OUT struct pointer of transfer timing config
|
|
/// @return E_MSPI_OK : succeed
|
|
/// @return E_MSPI_DCCONFIG_ERROR : failed to config transfer timing
|
|
//------------------------------------------------------------------------------
|
|
U8 MDrv_MSPI_DCConfig(struct mstar_spi *bs,U8 u8Channel, MSPI_DCConfig *ptDCConfig)
|
|
{
|
|
U8 errnum = E_MSPI_OK;
|
|
//check init
|
|
if(!gbInitFlag)
|
|
return E_MSPI_INIT_FLOW_ERROR;
|
|
|
|
if(ptDCConfig == NULL)
|
|
{
|
|
HAL_MSPI_Reset_DCConfig(bs,(MSPI_CH)u8Channel);
|
|
return E_MSPI_OK;
|
|
}
|
|
errnum = _MDrv_DC_TrStartSetting(bs,u8Channel,ptDCConfig->u8TrStart);
|
|
if(errnum != E_MSPI_OK)
|
|
goto ERROR_HANDLE;
|
|
errnum = _MDrv_DC_TrEndSetting(bs,u8Channel,ptDCConfig->u8TrEnd);
|
|
if(errnum != E_MSPI_OK)
|
|
goto ERROR_HANDLE;
|
|
errnum = _MDrv_DC_TBSetting(bs,u8Channel,ptDCConfig->u8TB);
|
|
if(errnum != E_MSPI_OK)
|
|
goto ERROR_HANDLE;
|
|
errnum = _MDrv_DC_TRWSetting(bs,u8Channel,ptDCConfig->u8TRW);
|
|
if(errnum != E_MSPI_OK)
|
|
goto ERROR_HANDLE;
|
|
return E_MSPI_OK;
|
|
|
|
ERROR_HANDLE:
|
|
errnum |= E_MSPI_DCCONFIG_ERROR;
|
|
return errnum;
|
|
}
|
|
|
|
void HAL_MSPI_SetCLKTiming(struct mstar_spi *bs,MSPI_CH eChannel, eCLK_config eCLKField, U8 u8CLKVal)
|
|
{
|
|
U16 u16TempBuf = 0;
|
|
mutex_lock(&hal_mspi_lock);
|
|
_HAL_MSPI_CheckandSetBaseAddr( eChannel);
|
|
switch(eCLKField) {
|
|
case E_MSPI_POL:
|
|
u16TempBuf = MSPI_READ(MSPI_CLK_CLOCK_OFFSET);
|
|
u16TempBuf &= ~(MSPI_CLK_POLARITY_MASK);
|
|
u16TempBuf |= u8CLKVal << MSPI_CLK_POLARITY_BIT_OFFSET;
|
|
break;
|
|
case E_MSPI_PHA:
|
|
u16TempBuf = MSPI_READ(MSPI_CLK_CLOCK_OFFSET);
|
|
u16TempBuf &= ~(MSPI_CLK_PHASE_MASK);
|
|
u16TempBuf |= u8CLKVal << MSPI_CLK_PHASE_BIT_OFFSET;
|
|
break;
|
|
case E_MSPI_CLK:
|
|
u16TempBuf = MSPI_READ(MSPI_CLK_CLOCK_OFFSET);
|
|
u16TempBuf &= MSPI_CLK_CLOCK_MASK;
|
|
u16TempBuf |= u8CLKVal << MSPI_CLK_CLOCK_BIT_OFFSET;
|
|
break;
|
|
}
|
|
MSPI_WRITE(MSPI_CLK_CLOCK_OFFSET, u16TempBuf);
|
|
|
|
mutex_unlock(&hal_mspi_lock);
|
|
}
|
|
|
|
void HAL_MSPI_SetLSB(struct mstar_spi *bs,MSPI_CH eChannel, BOOL enable)
|
|
{
|
|
mutex_lock(&hal_mspi_lock);
|
|
_HAL_MSPI_CheckandSetBaseAddr( eChannel);
|
|
|
|
MSPI_WRITE(MSPI_LSB_FIRST_OFFSET, enable);
|
|
|
|
mutex_unlock(&hal_mspi_lock);
|
|
}
|
|
|
|
#define NUM_SPI_CKG 4
|
|
#define NUM_SPI_CLKDIV 8
|
|
#define NUM_SPI_CLKRATES 32 //NUM_SPI_CKG * NUM_SPI_CLKDIVRATE
|
|
static U8 clk_spi_ckg[NUM_SPI_CKG] = {108, 54, 12, 144};
|
|
static U16 clk_spi_div[NUM_SPI_CLKDIV] = {2, 4, 8, 16, 32, 64, 128, 256};
|
|
static ST_DRV_MSPI_CLK clk_buffer[NUM_SPI_CLKRATES];
|
|
|
|
U32 HAL_MSPI_CLK_Config(struct mstar_spi *bs,U8 u8Chanel,U32 u32MspiClk)
|
|
{
|
|
U8 i = 0;
|
|
U8 j= 0;
|
|
U16 TempData = 0;
|
|
U32 clk =0;
|
|
ST_DRV_MSPI_CLK temp;
|
|
if(u8Chanel >=2)
|
|
return FALSE;
|
|
memset(&temp,0,sizeof(ST_DRV_MSPI_CLK));
|
|
memset(&clk_buffer,0,sizeof(ST_DRV_MSPI_CLK)*NUM_SPI_CLKRATES);
|
|
for(i = 0;i < NUM_SPI_CKG;i++)//clk_spi_m_p1
|
|
{
|
|
for(j = 0;j<NUM_SPI_CLKDIV;j++)//spi div
|
|
{
|
|
clk = clk_spi_ckg[i]*1000000;
|
|
clk_buffer[j+8*i].u8ClkSpi_cfg = i;
|
|
clk_buffer[j+8*i].u8ClkSpi_DIV = j ;
|
|
clk_buffer[j+8*i].u32ClkSpi = clk/clk_spi_div[j];
|
|
}
|
|
}
|
|
for(i = 0;i<NUM_SPI_CLKRATES;i++)
|
|
{
|
|
for(j = i;j<NUM_SPI_CLKRATES;j++)
|
|
{
|
|
if(clk_buffer[i].u32ClkSpi > clk_buffer[j].u32ClkSpi)
|
|
{
|
|
memcpy(&temp,&clk_buffer[i],sizeof(ST_DRV_MSPI_CLK));
|
|
|
|
memcpy(&clk_buffer[i],&clk_buffer[j],sizeof(ST_DRV_MSPI_CLK));
|
|
|
|
memcpy(&clk_buffer[j],&temp,sizeof(ST_DRV_MSPI_CLK));
|
|
}
|
|
}
|
|
}
|
|
for(i = 0;i<NUM_SPI_CLKRATES;i++)
|
|
{
|
|
if(u32MspiClk <= clk_buffer[i].u32ClkSpi)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (NUM_SPI_CLKRATES == i)
|
|
{
|
|
i--;
|
|
}
|
|
//match Closer clk
|
|
else if ((i) && ((u32MspiClk - clk_buffer[i-1].u32ClkSpi)<(clk_buffer[i].u32ClkSpi - u32MspiClk)))
|
|
{
|
|
i -= 1;
|
|
}
|
|
mspi_dbgmsg("[Lwc Debug] u8ClkSpi_P1 =%d\n",clk_buffer[i].u8ClkSpi_cfg);
|
|
mspi_dbgmsg("[Lwc Debug] u8ClkSpi_DIV =%d\n",clk_buffer[i].u8ClkSpi_DIV);
|
|
mspi_dbgmsg("[Lwc Debug] u32ClkSpi = %d\n",clk_buffer[i].u32ClkSpi);
|
|
|
|
if(u8Chanel == E_MSPI0)//mspi0
|
|
{
|
|
// CLK SETTING
|
|
TempData = CLK_READ(MSPI0_CLK_CFG);
|
|
TempData &= ~(MSPI0_CLK_MASK);
|
|
TempData |= (clk_buffer[i].u8ClkSpi_cfg<<2);
|
|
CLK_WRITE(MSPI0_CLK_CFG, TempData);
|
|
}
|
|
#if SUPPORT_SPI_1
|
|
else if(u8Chanel == E_MSPI1)//mspi1
|
|
{
|
|
// CLK SETTING
|
|
TempData = CLK_READ(MSPI1_CLK_CFG);
|
|
TempData &= ~(MSPI1_CLK_MASK);
|
|
TempData |= (clk_buffer[i].u8ClkSpi_cfg<<10);
|
|
CLK_WRITE(MSPI1_CLK_CFG, TempData);
|
|
}
|
|
#endif
|
|
TempData = MSPI_READ(MSPI_CLK_CLOCK_OFFSET);
|
|
TempData &= MSPI_CLK_CLOCK_MASK;
|
|
TempData |= clk_buffer[i].u8ClkSpi_DIV << MSPI_CLK_CLOCK_BIT_OFFSET;
|
|
MSPI_WRITE(MSPI_CLK_CLOCK_OFFSET, TempData);
|
|
|
|
return clk_buffer[i].u32ClkSpi;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
/// Description : config spi clock setting
|
|
/// @param ptCLKConfig \b OUT struct pointer of clock config
|
|
/// @return E_MSPI_OK : succeed
|
|
/// @return E_MSPI_CLKCONFIG_ERROR : failed to config spi clock
|
|
//------------------------------------------------------------------------------
|
|
U8 MDrv_MSPI_SetMode(struct mstar_spi *bs,U8 u8Channel, MSPI_Mode_Config_e eMode)
|
|
{
|
|
if (eMode >= E_MSPI_MODE_MAX) {
|
|
return E_MSPI_PARAM_OVERFLOW;
|
|
}
|
|
|
|
switch (eMode) {
|
|
case E_MSPI_MODE0:
|
|
HAL_MSPI_SetCLKTiming(bs,(MSPI_CH)u8Channel, E_MSPI_POL ,false);
|
|
HAL_MSPI_SetCLKTiming(bs,(MSPI_CH)u8Channel, E_MSPI_PHA ,false);
|
|
|
|
break;
|
|
case E_MSPI_MODE1:
|
|
HAL_MSPI_SetCLKTiming(bs,(MSPI_CH)u8Channel, E_MSPI_POL ,false);
|
|
HAL_MSPI_SetCLKTiming(bs,(MSPI_CH)u8Channel, E_MSPI_PHA ,true);
|
|
break;
|
|
case E_MSPI_MODE2:
|
|
HAL_MSPI_SetCLKTiming(bs,(MSPI_CH)u8Channel, E_MSPI_POL ,true);
|
|
HAL_MSPI_SetCLKTiming(bs,(MSPI_CH)u8Channel, E_MSPI_PHA ,false);
|
|
break;
|
|
case E_MSPI_MODE3:
|
|
HAL_MSPI_SetCLKTiming(bs,(MSPI_CH)u8Channel, E_MSPI_POL ,true);
|
|
HAL_MSPI_SetCLKTiming(bs,(MSPI_CH)u8Channel, E_MSPI_PHA ,true);
|
|
break;
|
|
default:
|
|
HAL_MSPI_Reset_CLKConfig(bs,(MSPI_CH)u8Channel);
|
|
return E_MSPI_OPERATION_ERROR;
|
|
}
|
|
|
|
return E_MSPI_OK;
|
|
}
|
|
|
|
void HAL_MSPI_SetPerFrameSize(struct mstar_spi *bs,MSPI_CH eChannel, BOOL bDirect, U8 u8BufOffset, U8 u8PerFrameSize)
|
|
{
|
|
U8 u8Index = 0;
|
|
U16 u16TempBuf = 0;
|
|
U8 u8BitOffset = 0;
|
|
U16 u16regIndex = 0;
|
|
|
|
mutex_lock(&hal_mspi_lock);
|
|
_HAL_MSPI_CheckandSetBaseAddr( eChannel);
|
|
if(bDirect == MSPI_READ_INDEX) {
|
|
u16regIndex = MSPI_FRAME_RBIT_OFFSET;
|
|
} else {
|
|
u16regIndex = MSPI_FRAME_WBIT_OFFSET;
|
|
}
|
|
if(u8BufOffset >=4) {
|
|
u8Index++;
|
|
u8BufOffset -= 4;
|
|
}
|
|
u8BitOffset = u8BufOffset * MSPI_FRAME_BIT_FIELD;
|
|
u16TempBuf = MSPI_READ(u16regIndex+ u8Index);
|
|
u16TempBuf &= ~(MSPI_FRAME_BIT_MASK << u8BitOffset);
|
|
u16TempBuf |= u8PerFrameSize << u8BitOffset;
|
|
MSPI_WRITE((u16regIndex + u8Index), u16TempBuf);
|
|
mutex_unlock(&hal_mspi_lock);
|
|
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/// Description : config spi transfer timing
|
|
/// @param ptDCConfig \b OUT struct pointer of bits of buffer tranferred to slave config
|
|
/// @return E_MSPI_OK : succeed
|
|
/// @return E_MSPI_FRAMECONFIG_ERROR : failed to config transfered bit per buffer
|
|
//------------------------------------------------------------------------------
|
|
U8 MDrv_MSPI_FRAMEConfig(struct mstar_spi *bs,U8 u8Channel, MSPI_FrameConfig *ptFrameConfig)
|
|
{
|
|
U8 errnum = E_MSPI_OK;
|
|
U8 u8Index = 0;
|
|
|
|
if(ptFrameConfig == NULL) {
|
|
HAL_MSPI_Reset_FrameConfig(bs,(MSPI_CH)u8Channel);
|
|
return E_MSPI_OK;
|
|
}
|
|
// read buffer bit config
|
|
for(u8Index = 0; u8Index < MAX_READ_BUF_SIZE; u8Index++) {
|
|
if(ptFrameConfig->u8RBitConfig[u8Index] > MSPI_FRAME_BIT_MAX) {
|
|
errnum = E_MSPI_PARAM_OVERFLOW;
|
|
} else {
|
|
HAL_MSPI_SetPerFrameSize(bs,(MSPI_CH)u8Channel, MSPI_READ_INDEX, u8Index, ptFrameConfig->u8RBitConfig[u8Index]);
|
|
}
|
|
}
|
|
//write buffer bit config
|
|
for(u8Index = 0; u8Index < MAX_WRITE_BUF_SIZE; u8Index++) {
|
|
if(ptFrameConfig->u8WBitConfig[u8Index] > MSPI_FRAME_BIT_MAX) {
|
|
errnum = E_MSPI_PARAM_OVERFLOW;
|
|
} else {
|
|
HAL_MSPI_SetPerFrameSize(bs,(MSPI_CH)u8Channel, MSPI_WRITE_INDEX, u8Index, ptFrameConfig->u8WBitConfig[u8Index]);
|
|
}
|
|
}
|
|
return errnum;
|
|
}
|
|
|
|
// add to sync code from utopia for localdimming to set clk
|
|
U32 MDrv_MSPI_SetCLK(struct mstar_spi *bs,U8 u8Channel, U32 u32MspiClk)
|
|
{
|
|
int u32SpiClk;
|
|
u32SpiClk = HAL_MSPI_CLK_Config(bs,(MSPI_CH)u8Channel,u32MspiClk);
|
|
return u32SpiClk;
|
|
}
|
|
|
|
void mspi_config(struct mstar_spi *bs,u8 u8Channel)
|
|
{
|
|
MSPI_DCConfig stDCConfig;
|
|
MSPI_FrameConfig stFrameConfig;
|
|
MSPI_Mode_Config_e mspimode = E_MSPI_MODE0;
|
|
stDCConfig.u8TB = 0;
|
|
stDCConfig.u8TrEnd = 0x0;
|
|
stDCConfig.u8TrStart = 0x0;
|
|
stDCConfig.u8TRW = 0;
|
|
|
|
memset(&stFrameConfig,0x07,sizeof(MSPI_FrameConfig));
|
|
MDrv_MSPI_Init(bs,u8Channel,bs->u32spi_mode);
|
|
MDrv_MSPI_DCConfig(bs,u8Channel, &stDCConfig);
|
|
MDrv_MSPI_SetMode(bs,u8Channel, mspimode);
|
|
MDrv_MSPI_FRAMEConfig(bs,u8Channel,&stFrameConfig);
|
|
MDrv_MSPI_SetCLK(bs,u8Channel,54000000); //200000 CLK
|
|
MDrv_MSPI_ChipSelect(bs,u8Channel,0,0);
|
|
HAL_MSPI_SetLSB(bs,u8Channel, 0);
|
|
return;
|
|
}
|
|
|
|
#ifdef _EN_MSPI_INTC_
|
|
static irqreturn_t mstar_spi_interrupt(int irq, void *dev_id)
|
|
{
|
|
struct spi_master *master = dev_id;
|
|
struct mstar_spi *bs = spi_master_get_devdata(master);
|
|
int uDoneFlag = 0;
|
|
//static int i=0;
|
|
|
|
uDoneFlag = _HAL_MSPI_CheckDone(bs);
|
|
|
|
if(uDoneFlag == 1){
|
|
|
|
complete(&bs->done);
|
|
mspi_dbgmsg("<<<<<<<<<<<<<<<<<<< SPI_0 Done >>>>>>>>>>>>>>>>>\n");
|
|
}else{
|
|
//printk("<<<<<<<<<<<<<<<<<<< SPI Fail >>>>>>>>>>>>>>>>>\n");
|
|
}
|
|
|
|
_HAL_MSPI_ClearDone();
|
|
|
|
return IRQ_HANDLED;
|
|
}
|
|
#endif
|
|
|
|
#if SUPPORT_SPI_1
|
|
static irqreturn_t mstar_spi_interrupt_spi1(int irq, void *dev_id)
|
|
{
|
|
struct spi_master *master = dev_id;
|
|
struct mstar_spi *bs = spi_master_get_devdata(master);
|
|
int uDoneFlag = 0;
|
|
//static int i=0;
|
|
|
|
uDoneFlag = _HAL_MSPI_CheckDone(bs);
|
|
|
|
if(uDoneFlag == 1){
|
|
|
|
complete(&bs->done);
|
|
mspi_dbgmsg("<<<<<<<<<<<<<<<<<<< SPI_1 Done >>>>>>>>>>>>>>>>>\n");
|
|
}else{
|
|
//printk("<<<<<<<<<<<<<<<<<<< SPI Fail >>>>>>>>>>>>>>>>>\n");
|
|
}
|
|
_HAL_MSPI_ClearDone();
|
|
|
|
return IRQ_HANDLED;
|
|
}
|
|
#endif
|
|
|
|
static int mstar_spi_start_transfer(struct spi_device *spi, struct spi_transfer *tfr)
|
|
{
|
|
struct mstar_spi *bs = spi_master_get_devdata(spi->master);
|
|
|
|
//printk("[mstar_spi_start_transfer]\n");
|
|
|
|
mspi_dbgmsg("All = %x\n",spi->mode);
|
|
mspi_dbgmsg("SPI mode = %d\n",spi->mode & 0x03);
|
|
mspi_dbgmsg("LSB first = %d\n",spi->mode & 0x08);
|
|
|
|
//reinit_completion(&bs->done);
|
|
bs->tx_buf = tfr->tx_buf;
|
|
bs->rx_buf = tfr->rx_buf;
|
|
bs->len = tfr->len;
|
|
|
|
MDrv_MSPI_ChipSelect(bs,_hal_msp.eCurrentCH,1,0);
|
|
|
|
/*if(tfr->speed_hz != NULL){
|
|
MDrv_MSPI_SetCLK(_hal_msp.eCurrentCH,tfr->speed_hz);
|
|
}*/
|
|
|
|
if((bs->tx_buf != NULL) && (bs->rx_buf != NULL))
|
|
{
|
|
MDrv_MSPI_FullDuplex(bs, _hal_msp.eCurrentCH, (U8 *)bs->tx_buf, (U8 *)bs->rx_buf, (U16)bs->len);
|
|
return 0;
|
|
}else if(bs->tx_buf != NULL){
|
|
mspi_dbgmsg("bs->tx_buf=%x,%x\n",bs->tx_buf[0],bs->tx_buf[1]);
|
|
|
|
if(bs->xfer_w_dma)
|
|
MDrv_MSPI_DMA_Write(bs, spi->master->bus_num,(U8 *)bs->tx_buf,(U16)bs->len);
|
|
else
|
|
MDrv_MSPI_Write(bs, _hal_msp.eCurrentCH,(U8 *)bs->tx_buf,(U16)bs->len);
|
|
}else if(bs->rx_buf != NULL){
|
|
if(bs->xfer_w_dma)
|
|
MDrv_MSPI_DMA_Read(bs,spi->master->bus_num,(U8 *)bs->rx_buf,(U16)bs->len);
|
|
else
|
|
MDrv_MSPI_Read(bs,_hal_msp.eCurrentCH,(U8 *)bs->rx_buf,(U16)bs->len);
|
|
|
|
mspi_dbgmsg("bs->rx_buf=%x,%x\n",bs->rx_buf[0],bs->rx_buf[1]);
|
|
}
|
|
//printk("bs->len=%d\n",bs->len);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int mstar_spi_finish_transfer(struct spi_device *spi,
|
|
struct spi_transfer *tfr, bool cs_change)
|
|
{
|
|
struct mstar_spi *bs = spi_master_get_devdata(spi->master);
|
|
|
|
//printk("[mstar_spi_finish_transfer] cs_change=%d\n",cs_change);
|
|
|
|
#if 1
|
|
|
|
if (tfr->delay_usecs)
|
|
udelay(tfr->delay_usecs);
|
|
|
|
if (cs_change){
|
|
/* Clear TA flag */
|
|
MDrv_MSPI_ChipSelect(bs,_hal_msp.eCurrentCH,0,0);
|
|
//MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, 0xFFFF);
|
|
}
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
static int mstar_spi_set_framecfg(struct mstar_spi *bs, int bits_per_word)
|
|
{
|
|
MSPI_FrameConfig stFrameConfig;
|
|
int i;
|
|
|
|
if (bits_per_word > MAX_SUPPORT_BITS)
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
else if (bits_per_word > 8)
|
|
{
|
|
for (i = 0; i < MAX_WRITE_BUF_SIZE; i+=2)
|
|
{
|
|
stFrameConfig.u8WBitConfig[i] = bits_per_word - 8 -1;
|
|
stFrameConfig.u8WBitConfig[i+1] = 8 -1;
|
|
}
|
|
for (i = 0; i < MAX_READ_BUF_SIZE; i+=2)
|
|
{
|
|
stFrameConfig.u8RBitConfig[i] = bits_per_word - 8 -1;
|
|
stFrameConfig.u8RBitConfig[i+1] = 8 -1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < MAX_WRITE_BUF_SIZE; i++)
|
|
{
|
|
stFrameConfig.u8WBitConfig[i] = bits_per_word -1;
|
|
}
|
|
for (i = 0; i < MAX_READ_BUF_SIZE; i++)
|
|
{
|
|
stFrameConfig.u8WBitConfig[i] = bits_per_word -1;
|
|
}
|
|
}
|
|
MDrv_MSPI_FRAMEConfig(bs,bs->u8channel,&stFrameConfig);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int mstar_spi_setup(struct spi_device *spi)
|
|
{
|
|
struct mstar_spi *bs = spi_master_get_devdata(spi->master);
|
|
|
|
MDrv_MSPI_SetMode(bs,bs->u8channel, spi->mode & MSTAR_SPI_MODE_BITS);
|
|
HAL_MSPI_SetLSB(bs,bs->u8channel,(spi->mode & SPI_LSB_FIRST)>>3);
|
|
spi->max_speed_hz = MDrv_MSPI_SetCLK(bs,bs->u8channel,spi->max_speed_hz);
|
|
bs->u32spi_mode = spi->mode & MSTAR_SPI_MODE_BITS;
|
|
|
|
// setup transfer bit mask
|
|
bs->xfer_w_dma = (spi->bits_per_word % 8 ==0) ? bs->use_dma : false;
|
|
bs->bits_per_word = spi->bits_per_word;
|
|
if (spi->bits_per_word > MAX_SUPPORT_BITS) {
|
|
return -EINVAL;
|
|
}
|
|
else if (spi->bits_per_word > 8) {
|
|
bs->wsize = 2;
|
|
}
|
|
else {
|
|
bs->wsize = 1;
|
|
}
|
|
mstar_spi_set_framecfg(bs, spi->bits_per_word);
|
|
|
|
mspi_dbgmsg("<~~~~~~~~~~~~~~~~>SETUP :%x,speed:%d channel:%d\n",spi->mode,spi->max_speed_hz,bs->u8channel);
|
|
return 0;
|
|
}
|
|
|
|
static int mstar_spi_transfer_one(struct spi_master *master,
|
|
struct spi_message *mesg)
|
|
{
|
|
struct mstar_spi *bs = spi_master_get_devdata(master);
|
|
struct spi_transfer *tfr;
|
|
struct spi_device *spi = mesg->spi;
|
|
int err = 0;
|
|
bool cs_change;
|
|
|
|
//mspi_dbgmsg("[mstar_spi_transfer_one]\n");
|
|
|
|
list_for_each_entry(tfr, &mesg->transfers, transfer_list) {
|
|
|
|
if (tfr->len % bs->wsize != 0) {
|
|
mspi_dbgmsg("invalid transfer len\n");
|
|
goto out;
|
|
}
|
|
|
|
err = mstar_spi_start_transfer(spi, tfr);
|
|
if (err){
|
|
mspi_dbgmsg("start_transfer err\n");
|
|
goto out;
|
|
}
|
|
|
|
cs_change = tfr->cs_change ||
|
|
list_is_last(&tfr->transfer_list, &mesg->transfers);
|
|
|
|
err = mstar_spi_finish_transfer(spi, tfr, cs_change);
|
|
if (err){
|
|
mspi_dbgmsg("finish transfer err\n");
|
|
goto out;
|
|
}
|
|
mesg->actual_length += bs->len;//(tfr->len - bs->len);
|
|
mspi_dbgmsg("transfered:%d\n",mesg->actual_length);
|
|
}
|
|
|
|
out:
|
|
/* Clear FIFOs, and disable the HW block */
|
|
mesg->status = err;
|
|
spi_finalize_current_message(master);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int mstar_spi_probe(struct platform_device *pdev)
|
|
{
|
|
struct spi_master *master;
|
|
struct mstar_spi *bs;
|
|
int err;
|
|
unsigned int u4IO_PHY_BASE;
|
|
unsigned int u4spi_bank[5];
|
|
#ifdef _EN_MSPI_INTC_
|
|
int irq;
|
|
#if SUPPORT_SPI_1
|
|
struct spi_master *master_spi1;
|
|
int irq2;
|
|
#endif
|
|
#endif
|
|
struct clk *clk;
|
|
struct clk_hw *hw_parent;
|
|
|
|
mspi_dbgmsg("<<<<<<<<<<<<<<<<< Probe >>>>>>>>>>>>>>>\n");
|
|
|
|
master = spi_alloc_master(&pdev->dev, sizeof(*bs));
|
|
if (!master) {
|
|
mspi_dbgmsg( "spi_alloc_master() failed\n");
|
|
dev_err(&pdev->dev, "spi_alloc_master() failed\n");
|
|
return -ENOMEM;
|
|
}
|
|
#if SUPPORT_SPI_1
|
|
master_spi1 = spi_alloc_master(&pdev->dev, sizeof(*bs));
|
|
if (!master_spi1) {
|
|
mspi_dbgmsg( "spi_alloc_master() failed\n");
|
|
dev_err(&pdev->dev, "spi_alloc_master() failed\n");
|
|
return -ENOMEM;
|
|
}
|
|
#endif
|
|
mspi_dbgmsg( "spi_alloc_master\n");
|
|
platform_set_drvdata(pdev, master);
|
|
#if SUPPORT_SPI_1
|
|
platform_set_drvdata(pdev, master_spi1);
|
|
#endif
|
|
|
|
master->mode_bits = MSTAR_SPI_MODE_BITS;
|
|
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, MAX_SUPPORT_BITS);
|
|
master->num_chipselect = 3;
|
|
master->transfer_one_message = mstar_spi_transfer_one;
|
|
master->dev.of_node = pdev->dev.of_node;
|
|
master->setup = mstar_spi_setup;
|
|
master->max_speed_hz = 54000000;
|
|
master->min_speed_hz = 46875;
|
|
master->bus_num = 0;
|
|
|
|
#if SUPPORT_SPI_1
|
|
master_spi1->mode_bits = MSTAR_SPI_MODE_BITS;
|
|
master_spi1->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, MAX_SUPPORT_BITS);
|
|
master_spi1->num_chipselect = 3;
|
|
master_spi1->transfer_one_message = mstar_spi_transfer_one;
|
|
master_spi1->dev.of_node = pdev->dev.of_node;
|
|
master_spi1->setup = mstar_spi_setup;
|
|
master_spi1->max_speed_hz = 54000000;
|
|
master_spi1->min_speed_hz = 46875;
|
|
master_spi1->bus_num = 1;
|
|
#endif
|
|
|
|
#ifdef _EN_MSPI_INTC_
|
|
irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
|
|
mspi_dbgmsg("[MSPI] Request IRQ: %d\n", irq);
|
|
if (request_irq(irq, mstar_spi_interrupt, 0, "MSPI_0 interrupt", (void*)master) == 0)
|
|
mspi_dbgmsg("[MSPI] MSPI_0 interrupt registered\n");
|
|
else
|
|
mspi_dbgmsg("[MSPI] MSPI_0 interrupt failed");
|
|
#if SUPPORT_SPI_1
|
|
irq2 = irq_of_parse_and_map(pdev->dev.of_node, 1);
|
|
mspi_dbgmsg("[MSPI] Request IRQ: %d\n", irq2);
|
|
if (request_irq(irq2, mstar_spi_interrupt_spi1, 0, "MSPI_1 interrupt", (void*)master_spi1) == 0)
|
|
mspi_dbgmsg("[MSPI] MSPI_1 interrupt registered\n");
|
|
else
|
|
mspi_dbgmsg("[MSPI] MSPI_1 interrupt failed");
|
|
#endif
|
|
#endif
|
|
|
|
of_property_read_u32(pdev->dev.of_node, "io_phy_addr", &u4IO_PHY_BASE);
|
|
of_property_read_u32_array(pdev->dev.of_node, "banks", (unsigned int*)u4spi_bank, 5);
|
|
|
|
//_hal_msp.eCurrentCH = E_MSPI1;
|
|
//_hal_msp.VirtMspBaseAddr = (char*)ioremap(BANK_TO_ADDR32(u4spi_bank[_hal_msp.eCurrentCH])+u4IO_PHY_BASE, BANK_SIZE);
|
|
//_hal_msp.VirtClkBaseAddr = (char*)ioremap(BANK_TO_ADDR32(u4spi_bank[2])+u4IO_PHY_BASE, BANK_SIZE);
|
|
//_hal_msp.VirtChiptopBaseAddr =(char*)ioremap(BANK_TO_ADDR32(u4spi_bank[3])+u4IO_PHY_BASE, BANK_SIZE);
|
|
|
|
mspi_dbgmsg("u4IO_PHY_BASE %x\n",u4IO_PHY_BASE);
|
|
mspi_dbgmsg("u4spi_bank[0] %x\n",u4spi_bank[0]);
|
|
mspi_dbgmsg("u4spi_bank[1] %x\n",u4spi_bank[1]);
|
|
mspi_dbgmsg("u4spi_bank[2] %x\n",u4spi_bank[2]);
|
|
mspi_dbgmsg("u4spi_bank[3] %x\n",u4spi_bank[3]);
|
|
mspi_dbgmsg("u4spi_bank[4] %x\n",u4spi_bank[4]);
|
|
|
|
bs = spi_master_get_devdata(master);
|
|
init_completion(&bs->done);
|
|
|
|
bs->VirtMspBaseAddr = (char*)ioremap(BANK_TO_ADDR32(u4spi_bank[0])+u4IO_PHY_BASE, BANK_SIZE);
|
|
bs->VirtClkBaseAddr = (char*)ioremap(BANK_TO_ADDR32(u4spi_bank[2])+u4IO_PHY_BASE, BANK_SIZE);
|
|
bs->VirtChiptopBaseAddr =(char*)ioremap(BANK_TO_ADDR32(u4spi_bank[3])+u4IO_PHY_BASE, BANK_SIZE);
|
|
bs->VirtMovdmaBaseAddr =(char*)ioremap(BANK_TO_ADDR32(u4spi_bank[4])+u4IO_PHY_BASE, BANK_SIZE);
|
|
|
|
bs->u8channel = E_MSPI0;
|
|
|
|
of_property_read_u32(pdev->dev.of_node, "spi0_mode", &bs->u32spi_mode);
|
|
bs->use_dma = false;
|
|
if (SUPPORT_DMA)
|
|
{
|
|
of_property_read_u32(pdev->dev.of_node, "dma", &bs->use_dma);
|
|
}
|
|
|
|
/* initialise the hardware */
|
|
mspi_config(bs,0);
|
|
|
|
#if SUPPORT_SPI_1
|
|
bs = spi_master_get_devdata(master_spi1);
|
|
init_completion(&bs->done);
|
|
bs->VirtMspBaseAddr = (char*)ioremap(BANK_TO_ADDR32(u4spi_bank[1])+u4IO_PHY_BASE, BANK_SIZE);
|
|
bs->VirtClkBaseAddr = (char*)ioremap(BANK_TO_ADDR32(u4spi_bank[2])+u4IO_PHY_BASE, BANK_SIZE);
|
|
bs->VirtChiptopBaseAddr =(char*)ioremap(BANK_TO_ADDR32(u4spi_bank[3])+u4IO_PHY_BASE, BANK_SIZE);
|
|
bs->VirtMovdmaBaseAddr =(char*)ioremap(BANK_TO_ADDR32(u4spi_bank[4])+u4IO_PHY_BASE, BANK_SIZE);
|
|
bs->u8channel = E_MSPI1;
|
|
|
|
of_property_read_u32(pdev->dev.of_node, "spi1_mode", &bs->u32spi_mode);
|
|
bs->use_dma = false;
|
|
if (SUPPORT_DMA)
|
|
{
|
|
of_property_read_u32(pdev->dev.of_node, "dma", &bs->use_dma);
|
|
}
|
|
|
|
/* initialise the hardware */
|
|
mspi_config(bs,1);
|
|
#endif
|
|
|
|
//2. set clk
|
|
clk = of_clk_get(pdev->dev.of_node, 0);
|
|
if(IS_ERR(clk))
|
|
{
|
|
err = PTR_ERR(clk);
|
|
mspi_dbgmsg("[%s]: of_clk_get failed\n", __func__);
|
|
}
|
|
else
|
|
{
|
|
/* select clock mux */
|
|
hw_parent = clk_hw_get_parent_by_index(__clk_get_hw(clk), 0); // select clock mux=0
|
|
mspi_dbgmsg( "[%s]parent_num:%d parent[0]:%s\n", __func__,
|
|
clk_hw_get_num_parents(__clk_get_hw(clk)), clk_hw_get_name(hw_parent));
|
|
clk_set_parent(clk, hw_parent->clk);
|
|
|
|
clk_prepare_enable(clk);
|
|
mspi_dbgmsg("[mspi] clk_prepare_enable\n");
|
|
}
|
|
|
|
err = devm_spi_register_master(&pdev->dev, master);
|
|
if (err) {
|
|
mspi_dbgmsg( "could not register SPI_0 master: %d\n", err);
|
|
dev_err(&pdev->dev, "could not register SPI master: %d\n", err);
|
|
goto out_master_put;
|
|
}
|
|
#if SUPPORT_SPI_1
|
|
err = devm_spi_register_master(&pdev->dev, master_spi1);
|
|
if (err) {
|
|
mspi_dbgmsg( "could not register SPI_1 master: %d\n", err);
|
|
dev_err(&pdev->dev, "could not register SPI master: %d\n", err);
|
|
goto out_master_put;
|
|
}
|
|
#endif
|
|
spi_new_device(master, &mstar_info);
|
|
#if SUPPORT_SPI_1
|
|
spi_new_device(master_spi1, &mstar_info);
|
|
#endif
|
|
return 0;
|
|
|
|
//out_clk_disable:
|
|
// clk_disable_unprepare(bs->clk);
|
|
out_master_put:
|
|
spi_master_put(master);
|
|
mspi_dbgmsg( "((((((((((( err:%d\n", err);
|
|
return err;
|
|
}
|
|
|
|
static int mstar_spi_remove(struct platform_device *pdev)
|
|
{
|
|
struct clk *clk;
|
|
|
|
#if 0
|
|
|
|
struct spi_master *master = platform_get_drvdata(pdev);
|
|
struct mstar_spi *bs = spi_master_get_devdata(master);
|
|
|
|
/* Clear FIFOs, and disable the HW block */
|
|
|
|
clk_disable_unprepare(bs->clk);
|
|
#endif
|
|
|
|
clk = of_clk_get(pdev->dev.of_node, 0);
|
|
if (IS_ERR(clk))
|
|
{
|
|
mspi_dbgmsg( "[SAR] Fail to get clk!\n" );
|
|
|
|
}
|
|
else
|
|
{
|
|
clk_disable_unprepare(clk);
|
|
clk_put(clk);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct of_device_id mstar_spi_match[] = {
|
|
{ .compatible = "sstar_spi", },
|
|
{}
|
|
};
|
|
MODULE_DEVICE_TABLE(of, mstar_spi_match);
|
|
|
|
static struct platform_driver mstar_spi_driver = {
|
|
.driver = {
|
|
.name = DRV_NAME,
|
|
.owner = THIS_MODULE,
|
|
.of_match_table = mstar_spi_match,
|
|
},
|
|
.probe = mstar_spi_probe,
|
|
.remove = mstar_spi_remove,
|
|
};
|
|
module_platform_driver(mstar_spi_driver);
|
|
|
|
MODULE_DESCRIPTION("SPI controller driver for Broadcom BCM2835");
|
|
MODULE_AUTHOR("Chris Boot <bootc@bootc.net>");
|
|
MODULE_LICENSE("GPL v2");
|