!28 feat: add spi driver for stm32mp157 soc.

Merge pull request !28 from 王亚枫/master
This commit is contained in:
openharmony_sig_ci
2022-03-21 03:02:53 +00:00
committed by Gitee
9 changed files with 1275 additions and 0 deletions
+1
View File
@@ -16,6 +16,7 @@ import("//drivers/adapter/khdf/liteos/hdf.gni")
group("drivers") {
deps = [
"adc",
"spi",
"gpio",
"i2c",
"iwdg",
+4
View File
@@ -25,6 +25,10 @@ ifeq ($(LOSCFG_DRIVERS_HDF_PLATFORM_ADC), y)
LIB_SUBDIRS += $(ST_DRIVERS_ROOT)/adc
endif
ifeq ($(LOSCFG_DRIVERS_HDF_PLATFORM_SPI), y)
LITEOS_BASELIB += -lhdf_spi
LIB_SUBDIRS += $(ST_DRIVERS_ROOT)/spi
endif
ifeq ($(LOSCFG_DRIVERS_HDF_PLATFORM_GPIO), y)
LITEOS_BASELIB += -lhdf_gpio
+42
View File
@@ -0,0 +1,42 @@
# Copyright (c) 2022 Huawei Device Co., Ltd. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this list of
# conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice, this list
# of conditions and the following disclaimer in the documentation and/or other materials
# provided with the distribution.
#
# 3. Neither the name of the copyright holder nor the names of its contributors may be used
# to endorse or promote products derived from this software without specific prior written
# permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import("//drivers/adapter/khdf/liteos/hdf.gni")
module_switch = defined(LOSCFG_DRIVERS_HDF_PLATFORM_SPI)
module_name = "hdf_SPI"
hdf_driver(module_name) {
sources = [
"stm32mp1_spi.c",
]
include_dirs = [
"." ,
"//device/st/drivers/stm32mp1xx_hal/STM32MP1xx_HAL_Driver/Inc",
]
}
+43
View File
@@ -0,0 +1,43 @@
# Copyright (c) 2022 Huawei Device Co., Ltd. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this list of
# conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice, this list
# of conditions and the following disclaimer in the documentation and/or other materials
# provided with the distribution.
#
# 3. Neither the name of the copyright holder nor the names of its contributors may be used
# to endorse or promote products derived from this software without specific prior written
# permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
include $(LITEOSTOPDIR)/config.mk
include $(LITEOSTOPDIR)/../../drivers/adapter/khdf/liteos/lite.mk
MODULE_NAME := hdf_spi
LOCAL_CFLAGS += $(HDF_INCLUDE)
LOCAL_SRCS += stm32mp1_spi.c
LOCAL_INCLUDE += -I ../stm32mp1xx_hal/STM32MP1xx_HAL_Driver/Inc
LOCAL_CFLAGS += -fstack-protector-strong -Wextra -Wall -Werror -fsigned-char -fno-strict-aliasing -fno-common
include $(HDF_DRIVER)
+945
View File
@@ -0,0 +1,945 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
*/
#include "stm32mp1_spi.h"
#include "device_resource_if.h"
#include "hdf_device_desc.h"
#include "hdf_log.h"
#include "osal_io.h"
#include "osal_mem.h"
#include "osal_irq.h"
#include "osal_time.h"
#include "stm32mp1xx.h"
#include "stm32mp1xx_hal_conf.h"
#include "spi_dev.h"
#define HDF_LOG_TAG stm32mp1_spi
static void Mp1xxSpiSetPinMux(struct Mp1xxSpiCntlr *stm32mp1)
{
uint32_t value;
uint32_t i;
volatile unsigned char *gpioZBase = NULL;
volatile unsigned char *gpioBase = NULL;
volatile unsigned char *tempBase = NULL;
gpioZBase = OsalIoRemap(MP1XX_AHB5_GPIOZ_BASE, MP1XX_GPIO_REG_SIZE);
if (gpioZBase == NULL) {
HDF_LOGE("%s: remap regbase failed", __func__);
return;
}
gpioBase = OsalIoRemap(MP1XX_AHB4_GPIO_BASE, MP1XX_GPIO_GROUP_STEP * MP1XX_GPIO_GROUP_NUM);
if (gpioBase == NULL) {
HDF_LOGE("%s: remap regbase failed", __func__);
return;
}
for (i = 0; i < MP1XX_SPI_PIN_NUM * MP1XX_MEMBER_PER_PIN; i += MP1XX_MEMBER_PER_PIN) {
if (stm32mp1->pins[i + PIN_GROUP] == MP1XX_GPIOZ) {
tempBase = gpioZBase;
} else if (stm32mp1->pins[i + PIN_GROUP] < MP1XX_GPIO_GROUP_NUM){
tempBase = gpioBase + MP1XX_GPIO_GROUP_STEP * stm32mp1->pins[i + PIN_GROUP];
}
value = OSAL_READL(tempBase);
value &= ~(MP1XX_MODER_MASK << (MP1XX_GPIO_MODE_BITS * stm32mp1->pins[i + PIN_NUM]));
value |= MP1XX_PIN_AF_MODE << (MP1XX_GPIO_MODE_BITS * stm32mp1->pins[i + PIN_NUM]);
OSAL_WRITEL(value, tempBase);
if (stm32mp1->pins[i + PIN_NUM] < MP1XX_PIN_NUM_PER_AF_REG) {
value = OSAL_READL(tempBase + MP1XX_GPIO_AF_LOW_REG);
value &= ~(MP1XX_GPIO_AF_MASK << (MP1XX_GPIO_AF_BITS * stm32mp1->pins[i + PIN_NUM]));
value |= stm32mp1->pins[i + PIN_AF] << (MP1XX_GPIO_AF_BITS * stm32mp1->pins[i + PIN_NUM]);
OSAL_WRITEL(value, tempBase + MP1XX_GPIO_AF_LOW_REG);
} else {
value = OSAL_READL(tempBase + MP1XX_GPIO_AF_HIGH_REG);
value &= ~(MP1XX_GPIO_AF_MASK <<
(MP1XX_GPIO_AF_BITS * stm32mp1->pins[i + PIN_NUM - MP1XX_PIN_NUM_PER_AF_REG]));
value |= stm32mp1->pins[i + PIN_AF] <<
(MP1XX_GPIO_AF_BITS * stm32mp1->pins[i + PIN_NUM - MP1XX_PIN_NUM_PER_AF_REG]);
OSAL_WRITEL(value, tempBase + MP1XX_GPIO_AF_HIGH_REG);
}
}
OsalIoUnmap((void *)gpioZBase);
OsalIoUnmap((void *)gpioBase);
}
static int32_t Mp1xxSpiCfgCs(struct Mp1xxSpiCntlr *stm32mp1, uint32_t cs)
{
uint32_t value;
if ((cs + 1) > stm32mp1->numCs) {
HDF_LOGE("%s: cs %d is big than stm32mp1 csNum %d", __func__, cs, stm32mp1->numCs);
return HDF_FAILURE;
}
if (stm32mp1->numCs == 1) {
return HDF_SUCCESS;
}
value = OSAL_READL(stm32mp1->regBase + MP1XX_SPI2S_CR1_OFFSET);
value &= ~MP1XX_SPI_CS;
value |= (!!cs ? (cs << MP1XX_SPI_CS_SHIFT) : 0);
OSAL_WRITEL(value, stm32mp1->regBase + MP1XX_SPI2S_CR1_OFFSET);
return HDF_SUCCESS;
}
/* open spi clk */
static void Mp1xxSpiHwInitCfg(struct Mp1xxSpiCntlr *stm32mp1)
{
switch (stm32mp1->busNum) {
case 1:
__HAL_RCC_SPI1_CLK_ENABLE();
break;
case 2:
__HAL_RCC_SPI2_CLK_ENABLE();
break;
case 3:
__HAL_RCC_SPI3_CLK_ENABLE();
break;
case 4:
__HAL_RCC_SPI4_CLK_ENABLE();
break;
case 5:
__HAL_RCC_SPI5_CLK_ENABLE();
break;
case 6:
__HAL_RCC_SPI6_CLK_ENABLE();
break;
default:
break;
}
}
/* close spi clk */
static void Mp1xxSpiHwExitCfg(struct Mp1xxSpiCntlr *stm32mp1)
{
switch (stm32mp1->busNum) {
case 1:
__HAL_RCC_SPI1_CLK_DISABLE();
break;
case 2:
__HAL_RCC_SPI2_CLK_DISABLE();
break;
case 3:
__HAL_RCC_SPI3_CLK_DISABLE();
break;
case 4:
__HAL_RCC_SPI4_CLK_DISABLE();
break;
case 5:
__HAL_RCC_SPI5_CLK_DISABLE();
break;
case 6:
__HAL_RCC_SPI6_CLK_DISABLE();
break;
default:
break;
}
}
static void Mp1xxSpiEnable(const struct Mp1xxSpiCntlr *stm32mp1)
{
uint32_t value;
value = OSAL_READL(stm32mp1->regBase + MP1XX_SPI2S_SR_OFFSET);
if ((value & MP1XX_SPI_MODF_MASK) != 0) {
value = OSAL_READL(stm32mp1->regBase + MP1XX_SPI2S_CR1_OFFSET);
value |= MP1XX_SPI_SSI;
OSAL_WRITEL(value, stm32mp1->regBase + MP1XX_SPI2S_CR1_OFFSET);
value = MP1XX_SPI_MODF_MASK;
OSAL_WRITEL(value, stm32mp1->regBase + MP1XX_SPI2S_IFCR_OFFSET);
}
value = OSAL_READL(stm32mp1->regBase + MP1XX_SPI2S_CR1_OFFSET);
value |= 0x1U;
OSAL_WRITEL(value, stm32mp1->regBase + MP1XX_SPI2S_CR1_OFFSET);
}
static void Mp1xxSpiDisable(const struct Mp1xxSpiCntlr *stm32mp1)
{
uint32_t value;
value = OSAL_READL(stm32mp1->regBase + MP1XX_SPI2S_CR1_OFFSET);
value &= ~0x1U;
OSAL_WRITEL(value, stm32mp1->regBase + MP1XX_SPI2S_CR1_OFFSET);
}
static void Mp1xxSpiConfigClk(const struct Mp1xxSpiCntlr *stm32mp1, uint32_t clkDiv)
{
uint32_t value;
uint32_t mbr;
clkDiv = clkDiv / MP1XX_SPI_MIN_CLK_DIV;
for (mbr = 0; mbr <= MP1XX_SPI_MBR_MAX; mbr++) {
if (clkDiv >> mbr == 0) {
mbr++;
HDF_LOGE("%s:mbr=%u", __func__, mbr);
break;
}
}
value = OSAL_READL(stm32mp1->regBase + MP1XX_SPI_CFG1_OFFSET);
value &= ~MP1XX_SPI_MBR_MASK;
//value |= mbr << MP1XX_SPI_MBR_SHIFT;
OSAL_WRITEL(value, stm32mp1->regBase + MP1XX_SPI_CFG1_OFFSET);
}
static void Mp1xxSpiConfigCfg1(const struct Mp1xxSpiCntlr *stm32mp1)
{
uint32_t value;
uint32_t temp;
temp = (stm32mp1->fifoSize > SPI_MAX_LEVEL) ? SPI_MAX_LEVEL : stm32mp1->fifoSize;
value = OSAL_READL(stm32mp1->regBase + MP1XX_SPI_CFG1_OFFSET);
value &= ~MP1XX_SPI_FTHLV_MASK;
value |= temp;
value &= ~MP1XX_SPI_DSIZE_MASK;
value |= stm32mp1->bitsPerWord - 1;
OSAL_WRITEL(value, stm32mp1->regBase + MP1XX_SPI_CFG1_OFFSET);
}
static void Mp1xxSpiConfigCfg2(const struct Mp1xxSpiCntlr *stm32mp1)
{
uint32_t tmp;
uint32_t value;
value = OSAL_READL(stm32mp1->regBase + MP1XX_SPI_CFG2_OFFSET);
value |= MP1XX_SPI_SSM;
tmp = (!!(stm32mp1->mode & SPI_CLK_PHASE)) ? (1 << MP1XX_SPI_CPHA_SHIFT) : 0;
value |= tmp;
tmp = (!!(stm32mp1->mode & SPI_CLK_POLARITY)) ? (1 << MP1XX_SPI_CPOL_SHIFT) : 0;
value |= tmp;
tmp = (!!(stm32mp1->mode & SPI_MODE_3WIRE)) ? (MP1XX_SPI_HALF_DUPLEX_MODE << MP1XX_SPI_COMM_SHIFT) : 0;
value |= tmp;
tmp = (!!(stm32mp1->mode & SPI_MODE_LSBFE)) ? (1 << MP1XX_SPI_LSBFRST_SHIFT) : 0;
value |= tmp;
value |= MP1XX_SPI_MASTER;
value |= MP1XX_SPI_SSOE_MASK;
OSAL_WRITEL(value, stm32mp1->regBase + MP1XX_SPI_CFG2_OFFSET);
}
static void Mp1xxSpiConfigFifo(const struct Mp1xxSpiCntlr *stm32mp1)
{
uint32_t value;
value = OSAL_READL(stm32mp1->regBase + MP1XX_SPI2S_HWCFGR_OFFSET);
/* Tx FIFO size 32 byte */
value &= ~MP1XX_SPI_FIFO_MASK;
value |= MP1XX_SPI2S_FIFO_SIZE;
/* Rx FIFO size 32 byte */
value &= ~(MP1XX_SPI_FIFO_MASK << MP1XX_SPI_RXFCFG_SHIFT);
value |= MP1XX_SPI2S_FIFO_SIZE << MP1XX_SPI_RXFCFG_SHIFT;
OSAL_WRITEL(value, stm32mp1->regBase + MP1XX_SPI2S_HWCFGR_OFFSET);
}
#define RX_INT_FIFO_LEVEL (256 - 128)
#define RX_INT_WAIT_TIMEOUT 1000 // ms
static void Mp1xxSpiConfigIrq(struct Mp1xxSpiCntlr *stm32mp1)
{
OSAL_WRITEL(SPI_ALL_IRQ_CLEAR, stm32mp1->regBase + MP1XX_SPI2S_IFCR_OFFSET);
if (stm32mp1->transferMode == SPI_POLLING_TRANSFER) {
OSAL_WRITEL(SPI_ALL_IRQ_DISABLE, stm32mp1->regBase + MP1XX_SPI2S_IER_OFFSET);
} else {
OSAL_WRITEL(SPI_ALL_IRQ_ENABLE, stm32mp1->regBase + MP1XX_SPI2S_IER_OFFSET);
}
}
static int32_t Mp1xxSpiConfig(struct Mp1xxSpiCntlr *stm32mp1)
{
uint32_t tmp;
uint32_t clkDiv;
/* Check if we can provide the requested rate */
if (stm32mp1->speed > stm32mp1->maxSpeedHz) {
HDF_LOGW("%s: invalid speed:%d, use max:%d instead", __func__, stm32mp1->speed, stm32mp1->maxSpeedHz);
stm32mp1->speed = stm32mp1->maxSpeedHz;
}
/* Min possible */
if (stm32mp1->speed == 0 || stm32mp1->speed < stm32mp1->minSpeedHz) {
HDF_LOGW("%s: invalid speed:%d, use min:%d instead", __func__, stm32mp1->speed, stm32mp1->minSpeedHz);
stm32mp1->speed = stm32mp1->minSpeedHz;
}
/* Check if we can provide the requested bits_per_word */
if ((stm32mp1->bitsPerWord < BITS_PER_WORD_MIN) || (stm32mp1->bitsPerWord > BITS_PER_WORD_MAX)) {
HDF_LOGE("%s: stm32mp1->bitsPerWord is %d not support", __func__, stm32mp1->bitsPerWord);
return HDF_FAILURE;
}
tmp = (stm32mp1->clkRate) / (stm32mp1->speed);
if (tmp < MP1XX_SPI_MIN_CLK_DIV) {
clkDiv = MP1XX_SPI_MIN_CLK_DIV;
} else if (tmp > MP1XX_SPI_MAX_CLK_DIV) {
clkDiv = MP1XX_SPI_MAX_CLK_DIV;
} else {
/* Calculate the closest division factor */
for (clkDiv = MP1XX_SPI_MIN_CLK_DIV; clkDiv < MP1XX_SPI_MAX_CLK_DIV; clkDiv = clkDiv << 1) {
if (clkDiv < tmp && (clkDiv << 1) > tmp) {
clkDiv = (((clkDiv << 1) - tmp) > (tmp - clkDiv)) ? clkDiv : (clkDiv << 1);
break;
}
}
HDF_LOGE("%s:clkDiv=%u", __func__, clkDiv);
}
Mp1xxSpiDisable(stm32mp1);
/* config SPICLK */
Mp1xxSpiConfigClk(stm32mp1, clkDiv);
/* config SPICFG1 register */
Mp1xxSpiConfigCfg1(stm32mp1);
/* config SPICFG2 register */
Mp1xxSpiConfigCfg2(stm32mp1);
/* config irq */
Mp1xxSpiConfigIrq(stm32mp1);
Mp1xxSpiEnable(stm32mp1);
return HDF_SUCCESS;
}
static int32_t Mp1xxSpiCheckTimeout(const struct Mp1xxSpiCntlr *stm32mp1)
{
uint32_t tmp = 0;
unsigned long value;
while (1) {
value = OSAL_READL(stm32mp1->regBase + MP1XX_SPI2S_SR_OFFSET);
if ((value & MP1XX_SPI_SR_RXP_MASK) != 0) {
break;
}
if (tmp++ > MAX_WAIT) {
HDF_LOGE("%s: spi transfer wait timeout", __func__);
return HDF_ERR_TIMEOUT;
}
OsalUDelay(1);
}
OSAL_WRITEL(SPI_ALL_IRQ_CLEAR, stm32mp1->regBase + MP1XX_SPI2S_IFCR_OFFSET);
return HDF_SUCCESS;
}
static int32_t Mp1xxSpiFlushFifo(const struct Mp1xxSpiCntlr *stm32mp1)
{
Mp1xxSpiDisable(stm32mp1);
OsalMDelay(1);
Mp1xxSpiEnable(stm32mp1);
return HDF_SUCCESS;
}
#define MP1XX_ONE_BYTE 1
#define MP1XX_TWO_BYTE 2
static inline uint8_t Mp1xxSpiToByteWidth(uint8_t bitsPerWord)
{
if (bitsPerWord <= BITS_PER_WORD_EIGHT) {
return MP1XX_ONE_BYTE;
} else {
return MP1XX_TWO_BYTE;
}
}
static void Mp1xxSpiWriteFifo(const struct Mp1xxSpiCntlr *stm32mp1, const uint8_t *tx, uint32_t count)
{
unsigned long value;
uint32_t delay = 0;
uint8_t bytes = Mp1xxSpiToByteWidth(stm32mp1->bitsPerWord);
for (value = 0; count >= bytes; count -= bytes) {
while (1) {
value = OSAL_READL(stm32mp1->regBase + MP1XX_SPI2S_SR_OFFSET);
if ((value & MP1XX_SPI_SR_TXP_MASK) != 0) {
break;
}
OsalUDelay(1);
delay++;
if (delay >= MAX_WAIT) {
HDF_LOGE("%s: write fifo time out", __func__);
break;
}
}
if (tx != NULL) {
value = (bytes == MP1XX_ONE_BYTE) ? *tx : *((uint16_t *)tx);
tx += bytes;
}
OSAL_WRITEL(value, stm32mp1->regBase + MP1XX_SPI2S_TXDR_OFFSET);
}
}
static void Mp1xxSpiReadFifo(const struct Mp1xxSpiCntlr *stm32mp1, uint8_t *rx, uint32_t count)
{
unsigned long value;
uint32_t delay = 0;
uint8_t bytes = Mp1xxSpiToByteWidth(stm32mp1->bitsPerWord);
while (1) {
value = OSAL_READL(stm32mp1->regBase + MP1XX_SPI2S_SR_OFFSET);
if ((value & MP1XX_SPI_SR_RXP_MASK) != 0) {
break;
}
OsalUDelay(1);
delay++;
if (delay >= MAX_WAIT) {
HDF_LOGE("%s: read fifo time out", __func__);
break;
}
}
for (value = 0; count >= bytes; count -= bytes) {
value = OSAL_READL(stm32mp1->regBase + MP1XX_SPI2S_RXDR_OFFSET);
if (rx == NULL) {
continue;
}
if (bytes == MP1XX_ONE_BYTE) {
*rx = (uint8_t)value;
} else {
*((uint16_t *)rx) = (uint16_t)value;
}
rx += bytes;
}
}
static void Mp1xxSpiStartTransfer(const struct Mp1xxSpiCntlr *stm32mp1)
{
uint32_t value;
value = OSAL_READL(stm32mp1->regBase + MP1XX_SPI2S_CR1_OFFSET);
value |= MP1XX_SPI_CSTART_MASK;
OSAL_WRITEL(value, stm32mp1->regBase + MP1XX_SPI2S_CR1_OFFSET);
}
static int32_t Mp1xxSpiTxRx(const struct Mp1xxSpiCntlr *stm32mp1, const struct SpiMsg *msg)
{
int32_t ret;
uint32_t tmpLen;
uint32_t len = msg->len;
const uint8_t *tx = msg->wbuf;
uint8_t *rx = msg->rbuf;
uint8_t bytes = Mp1xxSpiToByteWidth(stm32mp1->bitsPerWord);
uint32_t burstSize = stm32mp1->fifoSize * bytes;
if (tx == NULL && rx == NULL) {
return HDF_ERR_INVALID_PARAM;
}
if (stm32mp1->transferMode != SPI_POLLING_TRANSFER && RX_INT_FIFO_LEVEL < stm32mp1->fifoSize) {
burstSize = RX_INT_FIFO_LEVEL * bytes;
}
for (tmpLen = 0, len = msg->len; len > 0; len -= tmpLen) {
tmpLen = (len > burstSize) ? burstSize : len;
if (stm32mp1->transferMode != SPI_POLLING_TRANSFER && tmpLen == burstSize) {
OSAL_WRITEL(SPI_ALL_IRQ_ENABLE, stm32mp1->regBase + MP1XX_SPI2S_IER_OFFSET);
}
Mp1xxSpiWriteFifo(stm32mp1, tx, tmpLen);
Mp1xxSpiStartTransfer(stm32mp1);
tx = (tx == NULL) ? NULL : (tx + tmpLen);
if (stm32mp1->transferMode != SPI_POLLING_TRANSFER && tmpLen == burstSize) {
ret = OsalSemWait((struct OsalSem *)(&stm32mp1->sem), RX_INT_WAIT_TIMEOUT);
} else {
ret = Mp1xxSpiCheckTimeout(stm32mp1);
}
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: %s timeout", __func__, (stm32mp1->transferMode != SPI_POLLING_TRANSFER) ?
"wait rx fifo int" : "wait tx fifo idle");
return ret;
}
Mp1xxSpiReadFifo(stm32mp1, rx, tmpLen);
rx = (rx == NULL) ? NULL : (rx + tmpLen);
}
return HDF_SUCCESS;
}
static int32_t Mp1xxSpiSetCs(struct Mp1xxSpiCntlr *stm32mp1, uint32_t cs, uint32_t flag)
{
if (Mp1xxSpiCfgCs(stm32mp1, cs)) {
return HDF_FAILURE;
}
if (flag == SPI_CS_ACTIVE) {
Mp1xxSpiEnable(stm32mp1);
} else {
Mp1xxSpiDisable(stm32mp1);
}
return HDF_SUCCESS;
}
static struct SpiDev *Mp1xxSpiFindDeviceByCsNum(const struct Mp1xxSpiCntlr *stm32mp1, uint32_t cs)
{
struct SpiDev *dev = NULL;
struct SpiDev *tmpDev = NULL;
if (stm32mp1 == NULL || stm32mp1->numCs <= cs) {
return NULL;
}
DLIST_FOR_EACH_ENTRY_SAFE(dev, tmpDev, &(stm32mp1->deviceList), struct SpiDev, list) {
if (dev->csNum == cs) {
break;
}
}
return dev;
}
static int32_t Mp1xxSpiSetCfg(struct SpiCntlr *cntlr, struct SpiCfg *cfg)
{
struct Mp1xxSpiCntlr *stm32mp1 = NULL;
struct SpiDev *dev = NULL;
int32_t ret;
if (cntlr == NULL) {
HDF_LOGE("%s: cntlr is NULL", __func__);
return HDF_ERR_INVALID_PARAM;
}
if (cntlr->priv == NULL) {
HDF_LOGE("%s: priv is NULL", __func__);
return HDF_ERR_INVALID_PARAM;
}
if (cfg == NULL) {
HDF_LOGE("%s: cfg is NULL", __func__);
return HDF_ERR_INVALID_PARAM;
}
stm32mp1 = (struct Mp1xxSpiCntlr *)cntlr->priv;
dev = Mp1xxSpiFindDeviceByCsNum(stm32mp1, cntlr->curCs);
if (dev == NULL) {
return HDF_FAILURE;
}
dev->cfg.mode = cfg->mode;
dev->cfg.transferMode = cfg->transferMode;
if (cfg->bitsPerWord < BITS_PER_WORD_MIN || cfg->bitsPerWord > BITS_PER_WORD_MAX) {
HDF_LOGE("%s: bitsPerWord %d not support, use defaule bitsPerWord %d",
__func__, cfg->bitsPerWord, BITS_PER_WORD_EIGHT);
dev->cfg.bitsPerWord = BITS_PER_WORD_EIGHT;
} else {
dev->cfg.bitsPerWord = cfg->bitsPerWord;
}
if (cfg->maxSpeedHz != 0) {
dev->cfg.maxSpeedHz = cfg->maxSpeedHz;
}
ret = Mp1xxSpiConfig(stm32mp1);
if (ret != HDF_SUCCESS) {
return ret;
}
return HDF_SUCCESS;
}
static int32_t Mp1xxSpiGetCfg(struct SpiCntlr *cntlr, struct SpiCfg *cfg)
{
struct Mp1xxSpiCntlr *stm32mp1 = NULL;
struct SpiDev *dev = NULL;
if (cntlr == NULL || cntlr->priv == NULL || cfg == NULL) {
HDF_LOGE("%s: cntlr priv or cfg is NULL", __func__);
return HDF_ERR_INVALID_PARAM;
}
stm32mp1 = (struct Mp1xxSpiCntlr *)cntlr->priv;
dev = Mp1xxSpiFindDeviceByCsNum(stm32mp1, cntlr->curCs);
if (dev == NULL) {
return HDF_FAILURE;
}
*cfg = dev->cfg;
return HDF_SUCCESS;
}
static int32_t Mp1xxSpiTransferOneMessage(struct Mp1xxSpiCntlr *stm32mp1, struct SpiMsg *msg)
{
int32_t ret;
ret = Mp1xxSpiSetCs(stm32mp1, stm32mp1->curCs, SPI_CS_ACTIVE);
if (ret != HDF_SUCCESS) {
return ret;
}
ret = Mp1xxSpiFlushFifo(stm32mp1);
if (ret != HDF_SUCCESS) {
return ret;
}
stm32mp1->speed = (msg->speed) == 0 ? DEFAULT_SPEED : msg->speed;
ret = Mp1xxSpiConfig(stm32mp1);
if (ret != HDF_SUCCESS) {
return ret;
}
ret = Mp1xxSpiTxRx(stm32mp1, msg);
if (ret || msg->csChange) {
Mp1xxSpiSetCs(stm32mp1, stm32mp1->curCs, SPI_CS_INACTIVE);
}
return ret;
}
static int32_t Mp1xxSpiTransfer(struct SpiCntlr *cntlr, struct SpiMsg *msg, uint32_t count)
{
int32_t ret;
uint32_t i;
struct Mp1xxSpiCntlr *stm32mp1 = NULL;
struct SpiDev *dev = NULL;
if (cntlr == NULL || cntlr->priv == NULL) {
HDF_LOGE("%s: invalid controller", __func__);
return HDF_ERR_INVALID_OBJECT;
}
if (msg == NULL || (msg->rbuf == NULL && msg->wbuf == NULL) || count == 0) {
HDF_LOGE("%s: invalid parameter", __func__);
return HDF_ERR_INVALID_PARAM;
}
stm32mp1 = (struct Mp1xxSpiCntlr *)cntlr->priv;
dev = Mp1xxSpiFindDeviceByCsNum(stm32mp1, cntlr->curCs);
if (dev == NULL) {
return HDF_FAILURE;
}
Mp1xxSpiDisable(stm32mp1);
stm32mp1->mode = dev->cfg.mode;
stm32mp1->transferMode = dev->cfg.transferMode;
stm32mp1->bitsPerWord = dev->cfg.bitsPerWord;
stm32mp1->maxSpeedHz = dev->cfg.maxSpeedHz;
stm32mp1->curCs = dev->csNum;
for (i = 0; i < count; i++) {
ret = Mp1xxSpiTransferOneMessage(stm32mp1, &(msg[i]));
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: transfer error", __func__);
return ret;
}
}
return HDF_SUCCESS;
}
int32_t Mp1xxSpiOpen(struct SpiCntlr *cntlr)
{
(void)cntlr;
return HDF_SUCCESS;
}
int32_t Mp1xxSpiClose(struct SpiCntlr *cntlr)
{
(void)cntlr;
return HDF_SUCCESS;
}
static int32_t Mp1xxSpiProbe(struct Mp1xxSpiCntlr *stm32mp1)
{
int32_t ret;
Mp1xxSpiSetPinMux(stm32mp1);
Mp1xxSpiHwInitCfg(stm32mp1);
Mp1xxSpiConfigFifo(stm32mp1);
ret = Mp1xxSpiConfig(stm32mp1);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: Mp1xxSpiConfig error", __func__);
return ret;
}
return HDF_SUCCESS;
}
struct SpiCntlrMethod g_method = {
.Transfer = Mp1xxSpiTransfer,
.SetCfg = Mp1xxSpiSetCfg,
.GetCfg = Mp1xxSpiGetCfg,
.Open = Mp1xxSpiOpen,
.Close = Mp1xxSpiClose,
};
static int32_t Mp1xxSpiCreatAndInitDevice(struct Mp1xxSpiCntlr *stm32mp1)
{
uint32_t i;
struct SpiDev *device = NULL;
for (i = 0; i < stm32mp1->numCs; i++) {
device = (struct SpiDev *)OsalMemCalloc(sizeof(*device));
if (device == NULL) {
HDF_LOGE("%s: OsalMemCalloc error", __func__);
return HDF_FAILURE;
}
device->cntlr = stm32mp1->cntlr;
device->csNum = i;
device->cfg.bitsPerWord = stm32mp1->bitsPerWord;
device->cfg.transferMode = stm32mp1->transferMode;
device->cfg.maxSpeedHz = stm32mp1->maxSpeedHz;
device->cfg.mode = stm32mp1->mode;
DListHeadInit(&device->list);
DListInsertTail(&device->list, &stm32mp1->deviceList);
SpiAddDev(device);
}
return HDF_SUCCESS;
}
static void Mp1xxSpiRelease(struct Mp1xxSpiCntlr *stm32mp1)
{
struct SpiDev *dev = NULL;
struct SpiDev *tmpDev = NULL;
DLIST_FOR_EACH_ENTRY_SAFE(dev, tmpDev, &(stm32mp1->deviceList), struct SpiDev, list) {
SpiRemoveDev(dev);
DListRemove(&(dev->list));
OsalMemFree(dev);
}
if (stm32mp1->irqNum != 0) {
(void)OsalUnregisterIrq(stm32mp1->irqNum, stm32mp1);
}
OsalMemFree(stm32mp1);
}
static int32_t SpiGetBaseCfgFromHcs(struct Mp1xxSpiCntlr *stm32mp1, const struct DeviceResourceNode *node)
{
struct DeviceResourceIface *iface = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
if (iface == NULL || iface->GetUint8 == NULL || iface->GetUint16 == NULL || iface->GetUint32 == NULL) {
HDF_LOGE("%s: iface is invalid", __func__);
return HDF_FAILURE;
}
if (iface->GetUint32(node, "busNum", &stm32mp1->busNum, 0) != HDF_SUCCESS) {
HDF_LOGE("%s: read busNum fail", __func__);
return HDF_FAILURE;
}
if (iface->GetUint32(node, "spi_numCs", &stm32mp1->numCs, 0) != HDF_SUCCESS) {
HDF_LOGE("%s: read numCs fail", __func__);
return HDF_FAILURE;
}
if (iface->GetUint32(node, "spi_speed", &stm32mp1->speed, 0) != HDF_SUCCESS) {
HDF_LOGE("%s: read speed fail", __func__);
return HDF_FAILURE;
}
if (iface->GetUint32(node, "fifoSize", &stm32mp1->fifoSize, 0) != HDF_SUCCESS) {
HDF_LOGE("%s: read fifoSize fail", __func__);
return HDF_FAILURE;
}
if (iface->GetUint32(node, "spi_clkRate", &stm32mp1->clkRate, 0) != HDF_SUCCESS) {
HDF_LOGE("%s: read clkRate fail", __func__);
return HDF_FAILURE;
}
if (iface->GetUint16(node, "spi_mode", &stm32mp1->mode, 0) != HDF_SUCCESS) {
HDF_LOGE("%s: read mode fail", __func__);
return HDF_FAILURE;
}
if (iface->GetUint8(node, "spi_bitsPerWord", &stm32mp1->bitsPerWord, 0) != HDF_SUCCESS) {
HDF_LOGE("%s: read bitsPerWord fail", __func__);
return HDF_FAILURE;
}
if (iface->GetUint8(node, "spi_transferMode", &stm32mp1->transferMode, 0) != HDF_SUCCESS) {
HDF_LOGE("%s: read comMode fail", __func__);
return HDF_FAILURE;
}
return HDF_SUCCESS;
}
static int32_t SpiGetRegCfgFromHcs(struct Mp1xxSpiCntlr *stm32mp1, const struct DeviceResourceNode *node)
{
uint32_t regBasePhy;
uint32_t regSize;
int32_t ret;
struct DeviceResourceIface *iface = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
if (iface == NULL || iface->GetUint32 == NULL) {
HDF_LOGE("%s: face is invalid", __func__);
return HDF_FAILURE;
}
if (iface->GetUint32(node, "busModeSel", &stm32mp1->busModeSel, 0) != HDF_SUCCESS) {
HDF_LOGE("%s: read busModeSel fail", __func__);
return HDF_FAILURE;
}
if (stm32mp1->busModeSel != SPI2S_SPI_MODE) {
HDF_LOGI("%s: SPI%u is disabled", __func__, stm32mp1->busNum);
return HDF_ERR_NOT_SUPPORT;
}
if (iface->GetUint32(node, "regPBase", &regBasePhy, 0) != HDF_SUCCESS) {
HDF_LOGE("%s: read regBase fail", __func__);
return HDF_FAILURE;
}
if (iface->GetUint32(node, "regSize", &regSize, 0) != HDF_SUCCESS) {
HDF_LOGE("%s: read regSize fail", __func__);
return HDF_FAILURE;
}
stm32mp1->regBase = OsalIoRemap(regBasePhy, regSize);
if (stm32mp1->regBase == NULL) {
HDF_LOGE("%s: remap regbase failed", __func__);
return HDF_FAILURE;
}
if (iface->GetUint32(node, "irqNum", &stm32mp1->irqNum, 0) != HDF_SUCCESS) {
HDF_LOGE("%s: read irqNum fail", __func__);
return HDF_FAILURE;
}
ret = iface->GetUint8Array(node, "pins", stm32mp1->pins, MP1XX_SPI_PIN_NUM * MP1XX_MEMBER_PER_PIN, 0);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: read pins failed", __func__);
return ret;
}
return HDF_SUCCESS;
}
static uint32_t Mp1xxSpiIrqHandleNoShare(uint32_t irq, void *data)
{
unsigned long value;
struct Mp1xxSpiCntlr *stm32mp1 = (struct Mp1xxSpiCntlr *)data;
(void)irq;
if (stm32mp1 == NULL) {
HDF_LOGE("%s: data is NULL!", __func__);
return HDF_ERR_INVALID_PARAM;
}
value = OSAL_READL(stm32mp1->regBase + MP1XX_SPI2S_SR_OFFSET);
if ((value & MP1XX_SPI_MODF_MASK) != 0) {
HDF_LOGE("%s: mode fault detected", __func__);
return HDF_FAILURE;
}
OSAL_WRITEL(SPI_ALL_IRQ_CLEAR, stm32mp1->regBase + MP1XX_SPI2S_IFCR_OFFSET);
OSAL_WRITEL(SPI_ALL_IRQ_DISABLE, stm32mp1->regBase + MP1XX_SPI2S_IER_OFFSET);
(void)OsalSemPost(&stm32mp1->sem);
return HDF_SUCCESS;
}
static int32_t Mp1xxSpiInit(struct SpiCntlr *cntlr, const struct HdfDeviceObject *device)
{
int32_t ret;
struct Mp1xxSpiCntlr *stm32mp1 = NULL;
if (device->property == NULL) {
HDF_LOGE("%s: property is NULL", __func__);
return HDF_ERR_INVALID_PARAM;
}
stm32mp1 = (struct Mp1xxSpiCntlr *)OsalMemCalloc(sizeof(*stm32mp1));
if (stm32mp1 == NULL) {
HDF_LOGE("%s: OsalMemCalloc error", __func__);
return HDF_FAILURE;
}
ret = SpiGetRegCfgFromHcs(stm32mp1, device->property);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: SpiGetRegCfgFromHcs error", __func__);
OsalMemFree(stm32mp1);
return HDF_FAILURE;
}
ret = SpiGetBaseCfgFromHcs(stm32mp1, device->property);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: SpiGetBaseCfgFromHcs error", __func__);
OsalMemFree(stm32mp1);
return HDF_FAILURE;
}
stm32mp1->maxSpeedHz = MP1XX_SPI_MAX_SPEED;
stm32mp1->minSpeedHz = stm32mp1->clkRate / MP1XX_SPI_MAX_CLK_DIV;
DListHeadInit(&stm32mp1->deviceList);
stm32mp1->cntlr = cntlr;
cntlr->priv = stm32mp1;
cntlr->busNum = stm32mp1->busNum;
cntlr->method = &g_method;
ret = OsalSemInit(&stm32mp1->sem, 0);
if (ret != HDF_SUCCESS) {
OsalMemFree(stm32mp1);
HDF_LOGE("%s: sem init fail", __func__);
return ret;
}
if (stm32mp1->irqNum != 0) {
OSAL_WRITEL(SPI_ALL_IRQ_DISABLE, stm32mp1->regBase + MP1XX_SPI2S_IER_OFFSET);
ret = OsalRegisterIrq(stm32mp1->irqNum, 0, Mp1xxSpiIrqHandleNoShare, "SPI_MP1XX", stm32mp1);
if (ret != HDF_SUCCESS) {
OsalMemFree(stm32mp1);
HDF_LOGE("%s: regisiter irq %u fail", __func__, stm32mp1->irqNum);
(void)OsalSemDestroy(&stm32mp1->sem);
return ret;
}
}
ret = Mp1xxSpiCreatAndInitDevice(stm32mp1);
if (ret != HDF_SUCCESS) {
Mp1xxSpiRelease(stm32mp1);
return ret;
}
return HDF_SUCCESS;
}
static inline void Mp1xxSpiRemove(struct Mp1xxSpiCntlr *stm32mp1)
{
Mp1xxSpiHwExitCfg(stm32mp1);
OsalIoUnmap((void *)stm32mp1->regBase);
Mp1xxSpiRelease(stm32mp1);
}
static int32_t HdfSpiDeviceBind(struct HdfDeviceObject *device)
{
HDF_LOGI("%s: entry", __func__);
if (device == NULL) {
return HDF_ERR_INVALID_OBJECT;
}
return (SpiCntlrCreate(device) == NULL) ? HDF_FAILURE : HDF_SUCCESS;
}
static int32_t HdfSpiDeviceInit(struct HdfDeviceObject *device)
{
int32_t ret;
struct SpiCntlr *cntlr = NULL;
HDF_LOGI("%s: entry", __func__);
if (device == NULL) {
HDF_LOGE("%s: ptr is null", __func__);
return HDF_ERR_INVALID_OBJECT;
}
cntlr = SpiCntlrFromDevice(device);
if (cntlr == NULL) {
HDF_LOGE("%s: cntlr is null", __func__);
return HDF_FAILURE;
}
ret = Mp1xxSpiInit(cntlr, device);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: error init", __func__);
return HDF_FAILURE;
}
ret = Mp1xxSpiProbe(cntlr->priv);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: error probe", __func__);
}
return ret;
}
static void HdfSpiDeviceRelease(struct HdfDeviceObject *device)
{
struct SpiCntlr *cntlr = NULL;
HDF_LOGI("%s: entry", __func__);
if (device == NULL) {
HDF_LOGE("%s: device is null", __func__);
return;
}
cntlr = SpiCntlrFromDevice(device);
if (cntlr == NULL) {
HDF_LOGE("%s: cntlr is null", __func__);
return;
}
if (cntlr->priv != NULL) {
Mp1xxSpiRemove((struct Mp1xxSpiCntlr *)cntlr->priv);
}
SpiCntlrDestroy(cntlr);
}
struct HdfDriverEntry g_hdfSpiDevice = {
.moduleVersion = 1,
.moduleName = "stm32mp1_spi_driver",
.Bind = HdfSpiDeviceBind,
.Init = HdfSpiDeviceInit,
.Release = HdfSpiDeviceRelease,
};
HDF_INIT(g_hdfSpiDevice);
+148
View File
@@ -0,0 +1,148 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
*/
#ifndef __STM32MP1_SPI_H__
#define __STM32MP1_SPI_H__
#include "osal_sem.h"
#include "spi_core.h"
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
#define MP1XX_SPI2S_CR1_OFFSET 0x00
#define MP1XX_SPI_CR2_OFFSET 0x04
#define MP1XX_SPI_CFG1_OFFSET 0x08
#define MP1XX_SPI_CFG2_OFFSET 0x0C
#define MP1XX_SPI2S_IER_OFFSET 0x10
#define MP1XX_SPI2S_SR_OFFSET 0x14
#define MP1XX_SPI2S_IFCR_OFFSET 0x18
#define MP1XX_SPI2S_TXDR_OFFSET 0x20
#define MP1XX_SPI2S_RXDR_OFFSET 0x30
#define MP1XX_SPI_CRCPOLY_OFFSET 0x40
#define MP1XX_SPI_TXCRC_OFFSET 0x44
#define MP1XX_SPI_RXCRC_OFFSET 0x48
#define MP1XX_SPI_UDRDR_OFFSET 0x4C
#define MP1XX_SPI2S_CFGR_OFFSET 0x50
#define MP1XX_SPI2S_HWCFGR_OFFSET 0x3F0
#define MP1XX_SPI2S_VERR_OFFSET 0x3F4
#define MP1XX_SPI2S_IPIDR_OFFSET 0x3F8
#define MP1XX_SPI2S_SIDR_OFFSET 0x3FC
#define MP1XX_SPI_CS_SHIFT 12
#define MP1XX_SPI_CS (0x1U << MP1XX_SPI_CS_SHIFT)
#define MP1XX_SPI_SSI_SITFT 12
#define MP1XX_SPI_SSI (0x1U << MP1XX_SPI_SSI_SITFT)
#define MP1XX_SPI_MBR_SHIFT 28
#define MP1XX_SPI_MBR_MAX 0x7U
#define MP1XX_SPI_MBR_MASK (MP1XX_SPI_MBR_MAX << MP1XX_SPI_MBR_SHIFT)
#define MP1XX_SPI_SSM_SHIFT 26
#define MP1XX_SPI_SSM (0x1U << MP1XX_SPI_SSM_SHIFT)
#define MP1XX_SPI_CPOL_SHIFT 25
#define MP1XX_SPI_CPOL (0x1U << MP1XX_SPI_CPOL_SHIFT)
#define MP1XX_SPI_CPHA_SHIFT 24
#define MP1XX_SPI_CPHA (0x1U << MP1XX_SPI_CPHA_SHIFT)
#define MP1XX_SPI_LSBFRST_SHIFT 23
#define MP1XX_SPI_LSBFRST (0x1U << MP1XX_SPI_LSBFRST_SHIFT)
#define MP1XX_SPI_MASTER_SHIFT 22
#define MP1XX_SPI_MASTER (0x1U << MP1XX_SPI_MASTER_SHIFT)
#define MP1XX_SPI_COMM_SHIFT 17
#define MP1XX_SPI_COMM_MASK (0x3U << MP1XX_SPI_COMM_SHIFT)
#define MP1XX_SPI_HALF_DUPLEX_MODE 0x3U
#define MP1XX_SPI_FTHLV_SHIFT 5
#define MP1XX_SPI_FTHLV_MASK (0xFU << MP1XX_SPI_FTHLV_SHIFT)
#define MP1XX_SPI_DSIZE_MASK 0x1FU
#define MP1XX_SPI_DSIZE_MASK 0x1FU
#define MP1XX_SPI_FIFO_MASK 0xFU
#define MP1XX_SPI_RXFCFG_SHIFT 4
#define MP1XX_SPI_CSTART_MASK (0x1U << 9)
#define MP1XX_SPI_SR_TXP_MASK (0x1U << 1)
#define MP1XX_SPI_SR_RXP_MASK 0x1U
#define MP1XX_SPI_SR_TXTF_MASK 0x1U
#define MP1XX_SPI_MODF_MASK (0x1U << 9)
#define MP1XX_SPI_SSOE_MASK (0x1U << 29)
#define MP1XX_SPI2S_FIFO_SIZE 0x5 // 32 bytes
#define MP1XX_SPI_MAX_SPEED 50000000
#define MP1XX_SPI_MAX_CLK_DIV 128
#define MP1XX_SPI_MIN_CLK_DIV 16
#define BITS_PER_WORD_MIN 4
#define BITS_PER_WORD_EIGHT 8
#define BITS_PER_WORD_MAX 16
#define MAX_WAIT 10000
#define SPI_MAX_LEVEL 8
#define DEFAULT_SPEED 2000000
#define SPI_CS_ACTIVE 0
#define SPI_CS_INACTIVE 1
#define MP1XX_AHB4_GPIO_BASE 0x50002000
#define MP1XX_AHB5_GPIOZ_BASE 0x54004000
#define MP1XX_GPIOZ 25
#define MP1XX_GPIO_MODE_REG 0x0
#define MP1XX_GPIO_AF_LOW_REG 0x20
#define MP1XX_GPIO_AF_HIGH_REG 0x24
#define MP1XX_GPIO_MODE_BITS 2
#define MP1XX_MODER_MASK 0x3
#define MP1XX_GPIO_AF_BITS 4
#define MP1XX_GPIO_AF_MASK 0xF
#define MP1XX_GPIOZ 25
#define MP1XX_GPIO_GROUP_STEP 0x1000
#define MP1XX_GPIO_REG_SIZE 0x400
#define MP1XX_GPIO_GROUP_NUM 11
#define MP1XX_SPI_PIN_NUM 4
#define MP1XX_MEMBER_PER_PIN 3
#define MP1XX_PIN_AF_MODE 0x2
#define MP1XX_PIN_NUM_PER_AF_REG 8
#define SPI_ALL_IRQ_DISABLE 0x0
#define SPI_ALL_IRQ_ENABLE 0x205
#define SPI_RX_INTR_MASK 0x1
#define SPI_ALL_IRQ_CLEAR 0xFF8
enum busModeSel {
SPI2S_DISABLED = 0,
SPI2S_SPI_MODE = 1,
SPI2S_I2S_MODE = 2,
};
enum pinArray {
PIN_GROUP = 0,
PIN_NUM = 1,
PIN_AF = 2,
};
struct Mp1xxSpiCntlr {
struct SpiCntlr *cntlr;
struct DListHead deviceList;
struct OsalSem sem;
volatile unsigned char *regBase;
uint32_t irqNum;
uint32_t busNum;
uint32_t numCs;
uint32_t curCs;
uint32_t speed;
uint32_t fifoSize;
uint32_t clkRate;
uint32_t maxSpeedHz;
uint32_t minSpeedHz;
uint32_t busModeSel;
uint8_t pins[MP1XX_SPI_PIN_NUM * MP1XX_MEMBER_PER_PIN];
uint16_t mode;
uint8_t bitsPerWord;
uint8_t transferMode;
};
#ifdef __cplusplus
#if __cplusplus
}
#endif /* __cplusplus */
#endif /* __cplusplus */
#endif /* __STM32MP1_ADC_H__ */
@@ -58,6 +58,22 @@
deviceMatchAttr = "stm32mp1_uart_4";
}
}
device_spi :: device {
device0 :: deviceNode {
policy = 2;
priority = 40;
permission = 0644;
moduleName = "stm32mp1_spi_driver";
serviceName = "HDF_PLATFORM_SPI_1";
deviceMatchAttr = "st_stm32mp157_spi_1";
}
device1 :: deviceNode {
policy = 0;
priority = 50;
permission = 0644;
moduleName = "stm32mp157_spi_test";
}
}
device_mmc:: device {
device0 :: deviceNode {
+1
View File
@@ -1,5 +1,6 @@
#include "device_info/device_info.hcs"
#include "adc/adc_config.hcs"
#include "spi_i2s/spi_i2s_config.hcs"
#include "gpio/gpio_config.hcs"
#include "i2c/i2c_config.hcs"
#include "uart/uart_config.hcs"
@@ -0,0 +1,75 @@
root {
platform {
spi_i2s_config {
template stm32mp1_spi_i2s_device {
match_attr = "";
busModeSel = 1; // 0: Disabled; 1: SPI mode; 2: I2S mode.
regPBase = 0x44004000;
regSize = 0x400;
busNum = 0;
fifoSize = 4; // no more than 8.
spi_transferMode = 0;
spi_bitsPerWord = 8;
spi_mode = 19;
spi_clkRate = 200000000;
spi_speed = 10000000;
spi_numCs = 1;
/*
NSS SCK MISO MOSI
pins[port, pin, funcNum, ...]
<port> 0:GPIOA 1:GPIOB 2:GPIOC ...... 10:GPIOK 25:GPIOZ
<pin> 0:PIN0 1:PIN1 2:PIN2 ......
<funcNum> 0-15: AF0-AF15
*/
pins = [0, 4, 5, 0, 5, 5, 0, 6, 5, 0, 7, 5];
irqNum = 67;
}
controller_0x44004000 :: stm32mp1_spi_i2s_device {
match_attr = "st_stm32mp157_spi_1";
busNum = 1;
pins = [0, 0, 15, 25, 0, 5, 25, 1, 5, 25, 2, 5];
irqNum = 67;
}
controller_0x4000B000 :: stm32mp1_spi_i2s_device {
match_attr = "st_stm32mp157_spi_2";
regPBase = 0x4000B000;
busModeSel = 0;
busNum = 2;
pins = [1, 12, 5, 1, 13, 5, 1, 14, 5, 1, 15, 5];
irqNum = 68;
}
controller_0x4000C000 :: stm32mp1_spi_i2s_device {
match_attr = "st_stm32mp157_spi_3";
regPBase = 0x4000C000;
busModeSel = 0;
busNum = 3;
pins = [0, 15, 6, 2, 10, 6, 2, 11, 6, 2, 12, 6];
irqNum = 83;
}
controller_0x44005000 :: stm32mp1_spi_i2s_device {
match_attr = "st_stm32mp157_spi_4";
regPBase = 0x44005000;
busModeSel = 0;
busNum = 4;
pins = [4, 11, 5, 4, 12, 5, 4, 13, 5, 4, 14, 5];
irqNum = 116;
}
controller_0x44009000 :: stm32mp1_spi_i2s_device {
match_attr = "st_stm32mp157_spi_5";
regPBase = 0x44009000;
busModeSel = 0;
busNum = 5;
pins = [5, 6, 5, 5, 7, 5, 5, 8, 5, 5, 9, 5];
irqNum = 117;
}
controller_0x5C001000 :: stm32mp1_spi_i2s_device {
match_attr = "st_stm32mp157_spi_6";
regPBase = 0x5C001000;
busModeSel = 0;
busNum = 6;
pins = [6, 8, 5, 6, 13, 5, 6, 12, 5, 6, 14, 5];
irqNum = 118;
}
}
}
}