/* Copyright Statement: * * (C) 2005-2016 MediaTek Inc. All rights reserved. * * This software/firmware and related documentation ("MediaTek Software") are * protected under relevant copyright laws. The information contained herein * is confidential and proprietary to MediaTek Inc. ("MediaTek") and/or its licensors. * Without the prior written permission of MediaTek and/or its licensors, * any reproduction, modification, use or disclosure of MediaTek Software, * and information contained herein, in whole or in part, shall be strictly prohibited. * You may only use, reproduce, modify, or distribute (as applicable) MediaTek Software * if you have agreed to and been bound by the applicable license agreement with * MediaTek ("License Agreement") and been granted explicit permission to do so within * the License Agreement ("Permitted User"). If you are not a Permitted User, * please cease any access or use of MediaTek Software immediately. * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES * THAT MEDIATEK SOFTWARE RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES * ARE PROVIDED TO RECEIVER ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR * SUPPLIED WITH MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND * CUMULATIVE LIABILITY WITH RESPECT TO MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE MEDIATEK SOFTWARE AT ISSUE, * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. */ #include "hal_spi_master.h" #ifdef HAL_SPI_MASTER_MODULE_ENABLED #include <stdio.h> #include "type_def.h" //#include "mem_util.h" #include "timer.h" #include "top.h" #include "hal_spim.h" #include "nvic.h" //#include "dma_hw.h" #include "pinmux.h" #include "hal_gpio_7687.h" #include "mt7687.h" #include "hal_nvic.h" HALSPIM_ISR halspim_isr; void spim_irqhandler(hal_nvic_irq_t irq_number) { volatile UINT32 reg; //printf("SPIM IRQ!!\n"); halspim_isr(); reg = spi_reg_inl(SPI_REG_STATUS); // read to clear interrupt reg = reg; return; } void spim_isr_Register(HALSPIM_ISR spim_isr) { halspim_isr = spim_isr; } /* In real chip, spi module clock is 120Mhz Use below define can generate 4, 6, 8, 10, 12Mhz SPI_4M_DIV_VALUE, SPI_6M_DIV_VALUE SPI_8M_DIV_VALUE, SPI_10M_DIV_VALUE SPI_12M_DIV_VALUE */ INT32 halSpim_init(ULONG setting, ULONG clock) { /* TODO: reset SPI */ volatile UINT32 reg; volatile UINT32 *pTopCfgCM4PWRCtl = (volatile UINT32 *)TOP_CFG_CM4_PWR_CTL_CR; reg = cmnReadRegister32(pTopCfgCM4PWRCtl); reg = (reg >> CM4_MPLL_EN_SHIFT) & CM4_MPLL_EN_MASK; if (reg != CM4_MPLL_EN_PLL1_ON_PLL2_ON) { cmnPLL1ON_PLL2ON(KAL_TRUE); } if ((DRV_Reg32(TOP_CFG_HCLK_2M_CKGEN) & (1 << 17)) != 0) { DRV_Reg32(TOP_CFG_HCLK_2M_CKGEN) &= ~(1 << 17); delay_ms(500); } hal_nvic_register_isr_handler(CM4_SPIM_IRQ, spim_irqhandler); NVIC_SetPriority(CM4_SPIM_IRQ, CM4_SPIM_PRI); NVIC_EnableIRQ(CM4_SPIM_IRQ); /* TODO: use irq save */ /* Currently use default value: prefetch, spi_start_sel, cs_dsel_cnt, clock, clk_mode */ spi_reg_and(SPI_REG_MASTER, ~0xEFFF067B); spi_reg_or(SPI_REG_MASTER, setting | (clock << SPI_MASTER_CLOCK_DIV_SHIFT)); return 0; } INT32 spim_busy_wait(void) { int n = 60000; do { if ((spi_reg_inl(SPI_REG_CTL) & SPI_CTL_BUSY) == 0) { return 0; } } while (--n > 0); //printf("%s: fail \n", __func__); return -1; } INT32 spim_more_buf_trans_gpio(const UINT32 op_addr, const size_t n_cmd_byte, UINT8 *buf, const size_t buf_cnt, const ULONG flag) { UINT32 data; int i, q, r; int rc = -1; UINT8 *p_buf; /* step 0. enable more byte mode */ spi_reg_or(SPI_REG_MASTER, SPI_MASTER_MB_MODE_ENABLE); spi_reg_outl(SPI_REG_OPCODE, op_addr); spi_reg_outl(SPI_REG_MOREBUF, ((n_cmd_byte * 8) << 24)); /* step 2. write DI/DO data #0 ~ #7 */ if (flag & SPI_WRITE_FLAG) { if (buf == NULL) { goto RET_MB_TRANS; } q = buf_cnt / 4; r = buf_cnt % 4; p_buf = buf; for (i = 0; i < q; i++) { spi_reg_outl(SPI_REG_DATA(i), *(uint32_t *)p_buf); p_buf += 4; } if (r > 0) { data = 0; for (i = 0; i < r; i++) { data |= (*p_buf) << (8 * i); p_buf++; } spi_reg_outl(SPI_REG_DATA(q), data); } else { if (q < 8) { spi_reg_outl(SPI_REG_DATA(q), 0); } } } else { spi_reg_outl(SPI_REG_DATA(0), 0); } /* step 3. set rx (miso_bit_cnt) and tx (mosi_bit_cnt) bit count */ spi_reg_and(SPI_REG_MOREBUF, ~SPI_MBCTL_TX_RX_CNT_MASK); if (flag & SPI_WRITE_FLAG) { spi_reg_or(SPI_REG_MOREBUF, buf_cnt << 3); } else { spi_reg_or(SPI_REG_MOREBUF, (buf_cnt << 3 << 12)); } /* step 4. kick */ //DRV_WriteReg32(IOT_GPIO_AON_BASE + IOT_GPIO_DOUT2_RESET, (1 << 0)); //cs pull low spi_reg_or(SPI_REG_CTL, SPI_CTL_START); /* step 5. wait spi_master_busy */ spim_busy_wait(); //DRV_WriteReg32(IOT_GPIO_AON_BASE + IOT_GPIO_DOUT2_SET, (1 << 0)); if (flag & SPI_WRITE_FLAG) { rc = 0; goto RET_MB_TRANS; } /* step 6. read DI/DO data #0 */ if (flag & SPI_READ_FLAG) { if (buf == NULL) { //printf("%s: read null buf\n", __func__); return -1; } q = buf_cnt / 4; r = buf_cnt % 4; p_buf = buf; for (i = 0; i < q; i++) { *(uint32_t *)p_buf = spi_reg_inl(SPI_REG_DATA(i)); p_buf += 4; } if (r > 0) { data = spi_reg_inl(SPI_REG_DATA(q)); for (i = 0; i < r; i++) { *(p_buf + i) = (UINT8)(data >> (i * 8)); } } } rc = 0; RET_MB_TRANS: /* disable more-buf mode */ spi_reg_and(SPI_REG_MASTER, ~(SPI_MASTER_MB_MODE_ENABLE)); return rc; } INT32 spim_more_buf_trans_gpio_full_duplex(UINT32 op_addr, const size_t op_byte, const UINT8 *tx_buf, const size_t tx_byte, UINT8 *rx_buf, const size_t rx_byte) { UINT32 data; int i, q, r; UINT8 *p_buf; spi_reg_or(SPI_REG_MASTER, SPI_MASTER_MB_MODE_ENABLE); /* enable more byte mode */ //spi_reg_outl(SPI_REG_OPCODE, op_addr); spi_reg_or(SPI_REG_MASTER, (1 << 10)); /* enable full duplex mode */ /* write data to CMD register */ spi_reg_outl(SPI_REG_MOREBUF, ((op_byte * 8) << 24)); /* set cmd_bit_cnt to 32 */ spi_reg_outl(SPI_REG_OPCODE, op_addr); /* step 2. write DI/DO data #0 ~ #3 */ if (tx_byte > 0) { q = tx_byte / 4; r = tx_byte % 4; p_buf = (UINT8 *)tx_buf; for (i = 0; i < q; i++) { spi_reg_outl(SPI_REG_DATA(i), *(uint32_t *)p_buf); p_buf += 4; } if (r > 0) { data = 0; for (i = 0; i < r; i++) { data |= (*p_buf) << (8 * i); p_buf++; } spi_reg_outl(SPI_REG_DATA(q), data); q++; } for (i = q; i < 4; i++) { spi_reg_outl(SPI_REG_DATA(i), 0); } } else { for (i = 0; i < 4; i++) { spi_reg_outl(SPI_REG_DATA(i), 0); } } /* step 3. set rx (miso_bit_cnt) and tx (mosi_bit_cnt) bit count */ spi_reg_and(SPI_REG_MOREBUF, ~SPI_MBCTL_TX_RX_CNT_MASK); if (tx_byte >= rx_byte) { spi_reg_or(SPI_REG_MOREBUF, (tx_byte << 3) | (tx_byte << 3 << 12)); } else { spi_reg_or(SPI_REG_MOREBUF, (rx_byte << 3) | (rx_byte << 3 << 12)); } /* step 4. kick */ spi_reg_or(SPI_REG_CTL, SPI_CTL_START); /* step 5. wait spi_master_busy */ spim_busy_wait(); /* step 6. read DI/DO data #4 ~ #7 */ q = rx_byte / 4; r = rx_byte % 4; p_buf = rx_buf; for (i = 0; i < q; i++) { *(uint32_t *)p_buf = spi_reg_inl(SPI_REG_DATA(i + 4)); p_buf += 4; } if (r > 0) { data = spi_reg_inl(SPI_REG_DATA(q + 4)); for (i = 0; i < r; i++) { *(p_buf + i) = (UINT8)(data >> (i * 8)); } } /* disable more-buf mode and full duplex mode */ spi_reg_and(SPI_REG_MASTER, ~(SPI_MASTER_MB_MODE_ENABLE | DUPLEX_MASK)); return 0; } #endif /* HAL_SPI_MASTER_MODULE_ENABLED */