forked from 0xha0/df_datalink
first commit, new repo branches from datalink_repo
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
/***************************************************************************//**
|
||||
* @file xilinx/xilinx_axi_io.c
|
||||
* @brief Implementation of Xilinx AXI IO.
|
||||
* @author Antoniu Miclaus ([email protected])
|
||||
********************************************************************************
|
||||
* Copyright 2019(c) Analog Devices, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* - 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.
|
||||
* - Neither the name of Analog Devices, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
* - The use of this software may or may not infringe the patent rights
|
||||
* of one or more patent holders. This license does not release you
|
||||
* from the requirement that you obtain separate licenses from these
|
||||
* patent holders to use this software.
|
||||
* - Use of the software either in source or binary form, must be run
|
||||
* on or directly connected to an Analog Devices Inc. component.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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 Files **********************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#include <xil_io.h>
|
||||
#include "error.h"
|
||||
#include "axi_io.h"
|
||||
|
||||
/******************************************************************************/
|
||||
/************************ Functions Definitions *******************************/
|
||||
/******************************************************************************/
|
||||
|
||||
/**
|
||||
* @brief AXI IO Xilinx specific read function.
|
||||
* @param base - Base address
|
||||
* @param offset - Address offset
|
||||
* @param data - variable where returned data is stored
|
||||
* @return 0 in case of success, -1 otherwise.
|
||||
*/
|
||||
int32_t axi_io_read(uint32_t base, uint32_t offset, uint32_t *data)
|
||||
{
|
||||
*data = Xil_In32(base + offset);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief AXI IO Xilinx specific write function.
|
||||
* @param base - Base address
|
||||
* @param offset - Address offset
|
||||
* @param data - data to be written.
|
||||
* @return 0 in case of success, -1 otherwise.
|
||||
*/
|
||||
int32_t axi_io_write(uint32_t base, uint32_t offset, uint32_t data)
|
||||
{
|
||||
Xil_Out32(base + offset, data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
/***************************************************************************//**
|
||||
* @file xilinx/xilinx_delay.c
|
||||
* @brief Implementation of Xilinx Delay Functions.
|
||||
* @author Antoniu Miclaus ([email protected])
|
||||
********************************************************************************
|
||||
* Copyright 2019(c) Analog Devices, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* - 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.
|
||||
* - Neither the name of Analog Devices, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
* - The use of this software may or may not infringe the patent rights
|
||||
* of one or more patent holders. This license does not release you
|
||||
* from the requirement that you obtain separate licenses from these
|
||||
* patent holders to use this software.
|
||||
* - Use of the software either in source or binary form, must be run
|
||||
* on or directly connected to an Analog Devices Inc. component.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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 Files **********************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#include "delay.h"
|
||||
#include <sleep.h>
|
||||
#ifdef _XPARAMETERS_PS_H_
|
||||
#include "util.h"
|
||||
#include "xtime_l.h"
|
||||
#endif
|
||||
|
||||
/******************************************************************************/
|
||||
/************************ Functions Definitions *******************************/
|
||||
/******************************************************************************/
|
||||
|
||||
/**
|
||||
* @brief Generate microseconds delay.
|
||||
* @param usecs - Delay in microseconds.
|
||||
* @return None.
|
||||
*/
|
||||
void udelay(uint32_t usecs)
|
||||
{
|
||||
#ifdef _XPARAMETERS_PS_H_
|
||||
usleep(usecs);
|
||||
#else
|
||||
usleep_MB(usecs);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Generate miliseconds delay.
|
||||
* @param msecs - Delay in miliseconds.
|
||||
* @return None.
|
||||
*/
|
||||
void mdelay(uint32_t msecs)
|
||||
{
|
||||
#ifdef _XPARAMETERS_PS_H_
|
||||
usleep(msecs * 1000);
|
||||
#else
|
||||
usleep_MB(msecs * 1000);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get current time.
|
||||
* @return Current time structure from system start (seconds, microseconds).
|
||||
*/
|
||||
struct time get_time(void)
|
||||
{
|
||||
struct time t = {0, 0};
|
||||
#ifdef _XPARAMETERS_PS_H_
|
||||
unsigned long long Xtime_Global;
|
||||
uint32_t rem;
|
||||
|
||||
XTime_GetTime(&Xtime_Global);
|
||||
t.s = div_u64_rem(Xtime_Global, COUNTS_PER_SECOND, &rem);
|
||||
t.us = div_u64((uint64_t)rem * 1000000, COUNTS_PER_SECOND);
|
||||
#endif
|
||||
|
||||
return t;
|
||||
}
|
||||
@@ -0,0 +1,464 @@
|
||||
/***************************************************************************//**
|
||||
* @file xilinx/xilinx_gpio.c
|
||||
* @brief Implementation of Xilinx GPIO Generic Driver.
|
||||
* @author Antoniu Miclaus ([email protected])
|
||||
********************************************************************************
|
||||
* Copyright 2019(c) Analog Devices, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* - 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.
|
||||
* - Neither the name of Analog Devices, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
* - The use of this software may or may not infringe the patent rights
|
||||
* of one or more patent holders. This license does not release you
|
||||
* from the requirement that you obtain separate licenses from these
|
||||
* patent holders to use this software.
|
||||
* - Use of the software either in source or binary form, must be run
|
||||
* on or directly connected to an Analog Devices Inc. component.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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 Files **********************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <xparameters.h>
|
||||
#ifdef XPAR_XGPIO_NUM_INSTANCES
|
||||
#include <xgpio.h>
|
||||
#endif
|
||||
#ifdef XPAR_XGPIOPS_NUM_INSTANCES
|
||||
#include <xgpiops.h>
|
||||
#endif
|
||||
|
||||
#include "error.h"
|
||||
#include "gpio.h"
|
||||
#include "xilinx_gpio.h"
|
||||
|
||||
/******************************************************************************/
|
||||
/************************ Functions Definitions *******************************/
|
||||
/******************************************************************************/
|
||||
|
||||
/**
|
||||
* @brief Prepare the GPIO decriptor.
|
||||
* @param desc - The GPIO descriptor.
|
||||
* @param param - The structure that contains the GPIO parameters.
|
||||
* @return 0 in case of success, -1 otherwise.
|
||||
*/
|
||||
int32_t _gpio_init(struct gpio_desc *desc,
|
||||
const struct gpio_init_param *param)
|
||||
{
|
||||
int32_t ret;
|
||||
struct xil_gpio_desc *xdesc;
|
||||
struct xil_gpio_init_param *xinit;
|
||||
|
||||
ret = -1;
|
||||
|
||||
xdesc = desc->extra;
|
||||
xinit = param->extra;
|
||||
|
||||
xdesc->type = xinit->type;
|
||||
desc->number = param->number;
|
||||
|
||||
switch (xinit->type) {
|
||||
case GPIO_PL:
|
||||
#ifdef XGPIO_H
|
||||
xdesc->instance = (XGpio *)malloc(sizeof(XGpio));
|
||||
if(!xdesc->instance)
|
||||
goto pl_error;
|
||||
|
||||
xdesc->config = XGpio_LookupConfig(xinit->device_id);
|
||||
if(xdesc->config == NULL)
|
||||
goto pl_error;
|
||||
|
||||
ret = XGpio_CfgInitialize(xdesc->instance,
|
||||
xdesc->config,
|
||||
((XGpio_Config*)xdesc->config)
|
||||
->BaseAddress);
|
||||
if(ret < 0)
|
||||
goto pl_error;
|
||||
|
||||
break;
|
||||
pl_error:
|
||||
free(xdesc->instance);
|
||||
#endif
|
||||
goto error;
|
||||
case GPIO_PS:
|
||||
#ifdef XGPIOPS_H
|
||||
xdesc->instance = (XGpioPs *)malloc(sizeof(XGpioPs));
|
||||
if(!xdesc->instance)
|
||||
goto ps_error;
|
||||
|
||||
xdesc->config = XGpioPs_LookupConfig(xinit->device_id);
|
||||
if(xdesc->config == NULL)
|
||||
goto ps_error;
|
||||
|
||||
ret = XGpioPs_CfgInitialize(xdesc->instance,
|
||||
xdesc->config,
|
||||
((XGpioPs_Config*)xdesc->config)->BaseAddr);
|
||||
if(ret < 0)
|
||||
goto ps_error;
|
||||
break;
|
||||
ps_error:
|
||||
free(xdesc->instance);
|
||||
#endif
|
||||
goto error;
|
||||
error:
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Obtain the GPIO decriptor.
|
||||
* @param desc - The GPIO descriptor.
|
||||
* @param param - GPIO initialization parameters
|
||||
* @return 0 in case of success, -1 otherwise.
|
||||
*/
|
||||
int32_t xil_gpio_get(struct gpio_desc **desc,
|
||||
const struct gpio_init_param *param)
|
||||
{
|
||||
struct gpio_desc *descriptor;
|
||||
struct xil_gpio_desc *extra;
|
||||
int32_t ret;
|
||||
|
||||
descriptor = (struct gpio_desc *)malloc(sizeof(*descriptor));
|
||||
extra = (struct xil_gpio_desc*)malloc(sizeof(*extra));
|
||||
|
||||
if (!descriptor || !extra)
|
||||
return -1;
|
||||
|
||||
descriptor->extra = extra;
|
||||
ret = _gpio_init(descriptor, param);
|
||||
|
||||
if(ret != 0)
|
||||
goto error;
|
||||
|
||||
*desc = descriptor;
|
||||
|
||||
return 0;
|
||||
error:
|
||||
free(extra);
|
||||
free(descriptor);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the value of an optional GPIO.
|
||||
* @param desc - The GPIO descriptor.
|
||||
* @param param - GPIO Initialization parameters.
|
||||
* @return 0 in case of success, -1 otherwise.
|
||||
*/
|
||||
int32_t xil_gpio_get_optional(struct gpio_desc **desc,
|
||||
const struct gpio_init_param *param)
|
||||
{
|
||||
if(param == NULL) {
|
||||
*desc = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return xil_gpio_get(desc, param);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Free the resources allocated by gpio_get().
|
||||
* @param desc - The GPIO descriptor.
|
||||
* @return 0 in case of success, -1 otherwise.
|
||||
*/
|
||||
int32_t xil_gpio_remove(struct gpio_desc *desc)
|
||||
{
|
||||
if (desc != NULL) {
|
||||
free(((struct xil_gpio_desc *)(desc->extra))->instance);
|
||||
free(desc->extra);
|
||||
free(desc);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable the input direction of the specified GPIO.
|
||||
* @param desc - The GPIO descriptor.
|
||||
* @return 0 in case of success, -1 otherwise.
|
||||
*/
|
||||
int32_t xil_gpio_direction_input(struct gpio_desc *desc)
|
||||
{
|
||||
struct xil_gpio_desc *extra;
|
||||
#ifdef XGPIO_H
|
||||
uint8_t pin = desc->number;
|
||||
uint32_t channel = 1;
|
||||
uint32_t config = 0;
|
||||
#endif
|
||||
extra = desc->extra;
|
||||
|
||||
switch (extra->type) {
|
||||
case GPIO_PL:
|
||||
#ifdef XGPIO_H
|
||||
/* We assume that pin 32 is the first pin from channel 2 */
|
||||
if (pin >= 32) {
|
||||
channel = 2;
|
||||
pin -= 32;
|
||||
}
|
||||
|
||||
config = XGpio_GetDataDirection((XGpio *)extra->instance,
|
||||
channel);
|
||||
config |= (1 << pin);
|
||||
XGpio_SetDataDirection((XGpio *)extra->instance,
|
||||
channel,
|
||||
config);
|
||||
#endif
|
||||
break;
|
||||
case GPIO_PS:
|
||||
#ifdef XGPIOPS_H
|
||||
XGpioPs_SetDirectionPin(extra->instance,
|
||||
desc->number,
|
||||
GPIO_IN);
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable the output direction of the specified GPIO.
|
||||
* @param desc - The GPIO descriptor.
|
||||
* @param value - The value.
|
||||
* Example: GPIO_HIGH
|
||||
* GPIO_LOW
|
||||
* @return 0 in case of success, -1 otherwise.
|
||||
*/
|
||||
int32_t xil_gpio_direction_output(struct gpio_desc *desc,
|
||||
uint8_t value)
|
||||
{
|
||||
struct xil_gpio_desc *extra;
|
||||
#ifdef XGPIO_H
|
||||
uint8_t pin = desc->number;
|
||||
uint8_t channel;
|
||||
uint32_t reg_val;
|
||||
#endif
|
||||
extra = desc->extra;
|
||||
|
||||
switch (extra->type) {
|
||||
case GPIO_PL:
|
||||
#ifdef XGPIO_H
|
||||
if (pin >= 32) {
|
||||
channel = 2;
|
||||
pin -= 32;
|
||||
} else
|
||||
channel = 1;
|
||||
|
||||
reg_val = XGpio_GetDataDirection(extra->instance,
|
||||
channel);
|
||||
reg_val &= ~(1 << pin);
|
||||
XGpio_SetDataDirection(extra->instance,
|
||||
channel,
|
||||
reg_val);
|
||||
reg_val = XGpio_DiscreteRead(extra->instance,
|
||||
channel);
|
||||
if(value)
|
||||
reg_val |= (1 << pin);
|
||||
else
|
||||
reg_val &= ~(1 << pin);
|
||||
XGpio_DiscreteWrite(extra->instance,
|
||||
channel,
|
||||
reg_val);
|
||||
#endif
|
||||
break;
|
||||
case GPIO_PS:
|
||||
#ifdef XGPIOPS_H
|
||||
XGpioPs_SetDirectionPin(extra->instance,
|
||||
desc->number,
|
||||
GPIO_OUT);
|
||||
XGpioPs_SetOutputEnablePin(extra->instance,
|
||||
desc->number,
|
||||
GPIO_OUT);
|
||||
XGpioPs_WritePin(extra->instance,
|
||||
desc->number,
|
||||
value);
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the direction of the specified GPIO.
|
||||
* @param desc - The GPIO descriptor.
|
||||
* @param direction - The direction.
|
||||
* Example: GPIO_OUT
|
||||
* GPIO_IN
|
||||
* @return 0 in case of success, -1 otherwise.
|
||||
*/
|
||||
int32_t xil_gpio_get_direction(struct gpio_desc *desc,
|
||||
uint8_t *direction)
|
||||
{
|
||||
if (!desc)
|
||||
return -1;
|
||||
|
||||
struct xil_gpio_desc *extra;
|
||||
uint8_t pin = desc->number;
|
||||
|
||||
#ifdef XGPIO_H
|
||||
uint8_t channel;
|
||||
#endif
|
||||
extra = desc->extra;
|
||||
|
||||
switch (extra->type) {
|
||||
case GPIO_PL:
|
||||
#ifdef XGPIO_H
|
||||
if (pin >= 32) {
|
||||
channel = 2;
|
||||
pin -= 32;
|
||||
} else
|
||||
channel = 1;
|
||||
*direction = ((XGpio_GetDataDirection(extra->instance,
|
||||
channel) >> pin) & 0x1) ^ 0x1;
|
||||
#endif
|
||||
break;
|
||||
case GPIO_PS:
|
||||
#ifdef XGPIOPS_H
|
||||
*direction = XGpioPs_GetDirectionPin(extra->instance, pin);
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the value of the specified GPIO.
|
||||
* @param desc - The GPIO descriptor.
|
||||
* @param value - The value.
|
||||
* Example: GPIO_HIGH
|
||||
* GPIO_LOW
|
||||
* @return 0 in case of success, -1 otherwise.
|
||||
*/
|
||||
int32_t xil_gpio_set_value(struct gpio_desc *desc,
|
||||
uint8_t value)
|
||||
{
|
||||
struct xil_gpio_desc *extra;
|
||||
#ifdef XGPIO_H
|
||||
uint8_t pin = desc->number;
|
||||
uint8_t channel;
|
||||
uint32_t reg_val;
|
||||
#endif
|
||||
extra = desc->extra;
|
||||
|
||||
switch (extra->type) {
|
||||
case GPIO_PL:
|
||||
#ifdef XGPIO_H
|
||||
if (pin >= 32) {
|
||||
channel = 2;
|
||||
pin -= 32;
|
||||
} else
|
||||
channel = 1;
|
||||
|
||||
reg_val = XGpio_DiscreteRead(extra->instance, channel);
|
||||
if(value)
|
||||
reg_val |= (1 << pin);
|
||||
else
|
||||
reg_val &= ~(1 << pin);
|
||||
XGpio_DiscreteWrite(extra->instance, channel, reg_val);
|
||||
#endif
|
||||
break;
|
||||
case GPIO_PS:
|
||||
#ifdef XGPIOPS_H
|
||||
XGpioPs_WritePin(extra->instance, desc->number, value);
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the value of the specified GPIO.
|
||||
* @param desc - The GPIO descriptor.
|
||||
* @param value - The value.
|
||||
* Example: GPIO_HIGH
|
||||
* GPIO_LOW
|
||||
* @return 0 in case of success, -1 otherwise.
|
||||
*/
|
||||
int32_t xil_gpio_get_value(struct gpio_desc *desc,
|
||||
uint8_t *value)
|
||||
{
|
||||
if (!desc)
|
||||
return -1;
|
||||
|
||||
struct xil_gpio_desc *extra;
|
||||
uint8_t pin = desc->number;
|
||||
|
||||
#ifdef XGPIO_H
|
||||
uint8_t channel;
|
||||
#endif
|
||||
extra = desc->extra;
|
||||
|
||||
switch (extra->type) {
|
||||
case GPIO_PL:
|
||||
#ifdef XGPIO_H
|
||||
if (pin >= 32) {
|
||||
channel = 2;
|
||||
pin -= 32;
|
||||
} else
|
||||
channel = 1;
|
||||
*value = (XGpio_DiscreteRead(extra->instance, channel) >> pin) & 0x01;
|
||||
#endif
|
||||
break;
|
||||
case GPIO_PS:
|
||||
#ifdef XGPIOPS_H
|
||||
*value = XGpioPs_ReadPin(extra->instance, pin);
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Xilinx platform specific GPIO platform ops structure
|
||||
*/
|
||||
const struct gpio_platform_ops xil_gpio_ops = {
|
||||
.gpio_ops_get = &xil_gpio_get,
|
||||
.gpio_ops_get_optional = &xil_gpio_get_optional,
|
||||
.gpio_ops_remove = &xil_gpio_remove,
|
||||
.gpio_ops_direction_input = &xil_gpio_direction_input,
|
||||
.gpio_ops_direction_output = &xil_gpio_direction_output,
|
||||
.gpio_ops_get_direction = &xil_gpio_get_direction,
|
||||
.gpio_ops_set_value = &xil_gpio_set_value,
|
||||
.gpio_ops_get_value = &xil_gpio_get_value,
|
||||
};
|
||||
@@ -0,0 +1,95 @@
|
||||
/*******************************************************************************
|
||||
* @file xilinx/xilinx_gpio.h
|
||||
* @brief Header containing extra types used in the gpio driver
|
||||
* @author scuciurean ([email protected])
|
||||
********************************************************************************
|
||||
* Copyright 2019(c) Analog Devices, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* - 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.
|
||||
* - Neither the name of Analog Devices, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
* - The use of this software may or may not infringe the patent rights
|
||||
* of one or more patent holders. This license does not release you
|
||||
* from the requirement that you obtain separate licenses from these
|
||||
* patent holders to use this software.
|
||||
* - Use of the software either in source or binary form, must be run
|
||||
* on or directly connected to an Analog Devices Inc. component.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef XILINX_GPIO_H_
|
||||
#define XILINX_GPIO_H_
|
||||
|
||||
/******************************************************************************/
|
||||
/***************************** Include Files **********************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/******************************************************************************/
|
||||
/*************************** Types Declarations *******************************/
|
||||
/******************************************************************************/
|
||||
|
||||
/**
|
||||
* @enum xil_gpio_type
|
||||
* @brief Xilinx platform architecture sections
|
||||
*/
|
||||
enum xil_gpio_type {
|
||||
/** Programmable Logic */
|
||||
GPIO_PL,
|
||||
/** Processing System */
|
||||
GPIO_PS
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct xil_gpio_init_param
|
||||
* @brief Structure holding the initialization parameters for Xilinx platform
|
||||
* specific GPIO parameters.
|
||||
*/
|
||||
struct xil_gpio_init_param {
|
||||
/** Xilinx architecture */
|
||||
enum xil_gpio_type type;
|
||||
/** Device ID */
|
||||
uint32_t device_id;
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct xil_gpio_desc
|
||||
* @brief Xilinx platform specific GPIO descriptor
|
||||
*/
|
||||
struct xil_gpio_desc {
|
||||
/** Xilinx architecture */
|
||||
enum xil_gpio_type type;
|
||||
/** Xilinx GPIO configuration */
|
||||
void *config;
|
||||
/** Xilinx GPIO Instance */
|
||||
void *instance;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Xilinx platform specific gpio platform ops structure
|
||||
*/
|
||||
extern const struct gpio_platform_ops xil_gpio_ops;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,360 @@
|
||||
/***************************************************************************//**
|
||||
* @file xilinx/xilinx_gpio_irq.c
|
||||
* @brief Implementation of Xilinx GPIO IRQ Generic Driver.
|
||||
* @author Porumb Andrei ([email protected])
|
||||
********************************************************************************
|
||||
* Copyright 2021(c) Analog Devices, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* - 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.
|
||||
* - Neither the name of Analog Devices, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
* - The use of this software may or may not infringe the patent rights
|
||||
* of one or more patent holders. This license does not release you
|
||||
* from the requirement that you obtain separate licenses from these
|
||||
* patent holders to use this software.
|
||||
* - Use of the software either in source or binary form, must be run
|
||||
* on or directly connected to an Analog Devices Inc. component.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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 Files **********************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "xparameters.h"
|
||||
#include "error.h"
|
||||
#include "xilinx_gpio_irq.h"
|
||||
#include "util.h"
|
||||
#include "list.h"
|
||||
#include "irq.h"
|
||||
|
||||
/******************************************************************************/
|
||||
/************************ Functions Definitions *******************************/
|
||||
/******************************************************************************/
|
||||
|
||||
/**
|
||||
* @brief Comparing function used by list.
|
||||
* @param desc_a - Compared item
|
||||
* @param desc_b - Reference item
|
||||
* @return - 0 if items match
|
||||
*/
|
||||
static int32_t call_cmp(struct xil_callback_desc *desc_a,
|
||||
struct xil_callback_desc *desc_b)
|
||||
{
|
||||
return desc_a->pin_nb - desc_b->pin_nb;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function called when GPIO IRQ occurs.
|
||||
* @param param - GPIO IRQ desc's extra field
|
||||
* @return - None.
|
||||
*/
|
||||
static void xil_gpio_irq_handler(struct xil_gpio_irq_desc *param)
|
||||
{
|
||||
int32_t status = 0;
|
||||
int32_t pin_nb;
|
||||
struct xil_callback_desc *callback_desc;
|
||||
|
||||
status = iterator_move_to_idx(param->it, 0);
|
||||
while(!status) {
|
||||
iterator_read(param->it, &callback_desc);
|
||||
status = iterator_move(param->it, 1);
|
||||
if(XGpioPs_IntrGetStatusPin(¶m->my_Gpio, callback_desc->pin_nb))
|
||||
callback_desc->triggered = true;
|
||||
}
|
||||
|
||||
status = iterator_move_to_idx(param->it, 0);
|
||||
while(!status) {
|
||||
iterator_read(param->it, &callback_desc);
|
||||
status = iterator_move(param->it, 1);
|
||||
if(callback_desc->triggered == true) {
|
||||
callback_desc->triggered = false;
|
||||
XGpioPs_IntrDisablePin(¶m->my_Gpio, callback_desc->pin_nb);
|
||||
XGpioPs_IntrClearPin(¶m->my_Gpio, callback_desc->pin_nb);
|
||||
callback_desc->callback.legacy_callback(callback_desc->callback.ctx, 0U, NULL);
|
||||
if(callback_desc->enabled)
|
||||
XGpioPs_IntrEnablePin(¶m->my_Gpio, callback_desc->pin_nb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disable specific GPIO IRQ pin.
|
||||
* @param desc - The GPIO IRQ controller descriptor.
|
||||
* @param irq_id - Pin number.
|
||||
* @return 0 in case of success, -1 otherwise.
|
||||
*/
|
||||
int32_t xil_gpio_irq_disable(struct irq_ctrl_desc *desc, uint32_t irq_id)
|
||||
{
|
||||
int32_t status;
|
||||
struct xil_gpio_irq_desc *extra;
|
||||
struct xil_callback_desc *callback_desc;
|
||||
|
||||
extra = desc->extra;
|
||||
|
||||
status = iterator_move_to_idx(extra->it, 0);
|
||||
while(!status) {
|
||||
iterator_read(extra->it, &callback_desc);
|
||||
status = iterator_move(extra->it, 1);
|
||||
if(callback_desc->pin_nb == irq_id) {
|
||||
callback_desc->enabled = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
XGpioPs_IntrDisablePin(&extra->my_Gpio, irq_id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initialize the GPIO IRQ controller.
|
||||
* @param desc - The GPIO IRQ controller descriptor.
|
||||
* @param param - The GPIO IRQ controller initial parameters.
|
||||
* irq_ctrl_id from irq_init_param is the interrupt id for the parent controller
|
||||
* @return 0 in case of success, -1 otherwise.
|
||||
*/
|
||||
int32_t xil_gpio_irq_ctrl_init(struct irq_ctrl_desc **desc,
|
||||
const struct irq_init_param *param)
|
||||
{
|
||||
int32_t i;
|
||||
int32_t status;
|
||||
struct irq_ctrl_desc *ldesc;
|
||||
static XGpioPs_Config *GPIO_Config;
|
||||
struct xil_gpio_irq_desc *xil_desc;
|
||||
struct xil_gpio_irq_init_param *xil_ip;
|
||||
struct callback_desc callback;
|
||||
|
||||
xil_desc = (struct xil_gpio_irq_desc *)calloc(1, sizeof(*xil_desc));
|
||||
if(!xil_desc)
|
||||
return -ENOMEM;
|
||||
|
||||
ldesc = (struct irq_ctrl_desc *)calloc(1, sizeof(*ldesc));
|
||||
if(!ldesc) {
|
||||
free(xil_desc);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
xil_ip = param->extra;
|
||||
GPIO_Config = XGpioPs_LookupConfig(xil_ip->gpio_device_id);
|
||||
status = XGpioPs_CfgInitialize(&xil_desc->my_Gpio, GPIO_Config,
|
||||
GPIO_Config->BaseAddr);
|
||||
if(status)
|
||||
goto error_desc;
|
||||
|
||||
ldesc->extra = xil_desc;
|
||||
xil_desc->parent_desc = xil_ip->parent_desc;
|
||||
|
||||
status = list_init(&xil_desc->callback_list, LIST_DEFAULT,
|
||||
call_cmp);
|
||||
if(status)
|
||||
goto error_list;
|
||||
|
||||
status = iterator_init(&xil_desc->it, xil_desc->callback_list, 0);
|
||||
if(status) {
|
||||
iterator_remove(xil_desc->it);
|
||||
goto error_list;
|
||||
}
|
||||
|
||||
ldesc->irq_ctrl_id = param->irq_ctrl_id;
|
||||
status = irq_trigger_level_set(xil_desc->parent_desc, ldesc->irq_ctrl_id,
|
||||
IRQ_EDGE_RISING);
|
||||
if(status)
|
||||
goto error_op;
|
||||
|
||||
status = irq_enable(xil_desc->parent_desc, ldesc->irq_ctrl_id);
|
||||
if(status)
|
||||
goto error_op;
|
||||
|
||||
callback.legacy_callback = &xil_gpio_irq_handler;
|
||||
callback.ctx = ldesc->extra;
|
||||
status = irq_register_callback(xil_desc->parent_desc, ldesc->irq_ctrl_id,
|
||||
&callback);
|
||||
if(status)
|
||||
goto error_op;
|
||||
|
||||
*desc = ldesc;
|
||||
|
||||
return 0;
|
||||
|
||||
error_op:
|
||||
iterator_remove(xil_desc->it);
|
||||
error_list:
|
||||
list_remove(xil_desc->callback_list);
|
||||
error_desc:
|
||||
free(xil_desc);
|
||||
free(ldesc);
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set GPIO interrupt trigger level.
|
||||
* @param desc - The GPIO IRQ controller descriptor.
|
||||
* @param irq_id - Pin number.
|
||||
* @param trig - New trigger level for the GPIO interrupt.
|
||||
* @return 0 in case of success, -1 otherwise.
|
||||
*/
|
||||
int32_t xil_gpio_irq_trigger_level_set(struct irq_ctrl_desc *desc,
|
||||
uint32_t irq_id,
|
||||
enum irq_trig_level trig)
|
||||
{
|
||||
static const int32_t trig_level[5] = {XGPIOPS_IRQ_TYPE_LEVEL_LOW,
|
||||
XGPIOPS_IRQ_TYPE_LEVEL_HIGH,
|
||||
XGPIOPS_IRQ_TYPE_EDGE_FALLING,
|
||||
XGPIOPS_IRQ_TYPE_EDGE_RISING,
|
||||
XGPIOPS_IRQ_TYPE_EDGE_BOTH
|
||||
};
|
||||
struct xil_gpio_irq_desc *extra;
|
||||
|
||||
extra = desc->extra;
|
||||
XGpioPs_SetIntrTypePin(&extra->my_Gpio, irq_id, trig_level[trig]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Register pin specific GPIO interrupt.
|
||||
* @param desc - The GPIO IRQ controller descriptor.
|
||||
* @param irq_id - Pin number.
|
||||
* @param callback_desc - Callback.
|
||||
* @return 0 in case of success, -1 otherwise.
|
||||
*/
|
||||
int32_t xil_gpio_irq_register_callback(struct irq_ctrl_desc *desc,
|
||||
uint32_t irq_id,
|
||||
struct callback_desc *callback_desc)
|
||||
{
|
||||
struct xil_callback_desc *dev_callback;
|
||||
struct xil_gpio_irq_desc *extra;
|
||||
|
||||
dev_callback = (struct xil_callback_desc *)calloc(1,
|
||||
sizeof(*dev_callback));
|
||||
if(!dev_callback)
|
||||
return -1;
|
||||
|
||||
dev_callback->pin_nb = irq_id;
|
||||
dev_callback->callback.legacy_callback = callback_desc->legacy_callback;
|
||||
dev_callback->callback.ctx = callback_desc->ctx;
|
||||
dev_callback->triggered = false;
|
||||
|
||||
extra = desc->extra;
|
||||
XGpioPs_SetDirectionPin(&extra->my_Gpio, irq_id, 0);
|
||||
list_add_last(extra->callback_list, dev_callback);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Unregister pin specific GPIO interrupt.
|
||||
* @param desc - The GPIO IRQ controller descriptor.
|
||||
* @param irq_id - Pin number.
|
||||
* @param cb - Callback descriptor.
|
||||
* @return 0 in case of success, -1 otherwise.
|
||||
*/
|
||||
int32_t xil_gpio_irq_unregister_callback(struct irq_ctrl_desc *desc,
|
||||
uint32_t irq_id, struct callback_desc *cb)
|
||||
{
|
||||
int32_t status;
|
||||
struct xil_gpio_irq_desc *extra;
|
||||
struct xil_callback_desc *dev_callback;
|
||||
struct xil_callback_desc search_callback;
|
||||
|
||||
extra = desc->extra;
|
||||
search_callback.pin_nb = irq_id;
|
||||
status = list_get_find(extra->callback_list, &dev_callback,
|
||||
&search_callback);
|
||||
if(status)
|
||||
return -ENXIO;
|
||||
|
||||
free(dev_callback);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable specific GPIO IRQ pin.
|
||||
* @param desc - The GPIO IRQ controller descriptor.
|
||||
* @param irq_id - Pin number.
|
||||
* @return 0 in case of success, -1 otherwise.
|
||||
*/
|
||||
int32_t xil_gpio_irq_enable(struct irq_ctrl_desc *desc, uint32_t irq_id)
|
||||
{
|
||||
int32_t status;
|
||||
struct xil_gpio_irq_desc *extra;
|
||||
struct xil_callback_desc *callback_desc;
|
||||
|
||||
extra = desc->extra;
|
||||
|
||||
status = iterator_move_to_idx(extra->it, 0);
|
||||
while(!status) {
|
||||
iterator_read(extra->it, &callback_desc);
|
||||
status = iterator_move(extra->it, 1);
|
||||
if(callback_desc->pin_nb == irq_id) {
|
||||
callback_desc->enabled = true;
|
||||
XGpioPs_IntrClearPin(&extra->my_Gpio, irq_id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
XGpioPs_IntrEnablePin(&extra->my_Gpio, irq_id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Remove the GPIO IRQ controller.
|
||||
* @param desc - The GPIO IRQ controller descriptor.
|
||||
* @return 0 in case of success, -1 otherwise.
|
||||
*/
|
||||
int32_t xil_gpio_irq_ctrl_remove(struct irq_ctrl_desc *desc)
|
||||
{
|
||||
struct xil_gpio_irq_desc *extra;
|
||||
struct xil_callback_desc *callback_desc;
|
||||
|
||||
if (!desc)
|
||||
return -EINVAL;
|
||||
|
||||
extra = desc->extra;
|
||||
while (0 == list_get_first(extra->callback_list, &callback_desc))
|
||||
free(callback_desc);
|
||||
|
||||
iterator_remove(extra->it);
|
||||
list_remove(extra->callback_list);
|
||||
free(extra);
|
||||
free(desc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Xilinx platform specific GPIO IRQ platform ops structure
|
||||
*/
|
||||
const struct irq_platform_ops xil_gpio_irq_ops = {
|
||||
.init = &xil_gpio_irq_ctrl_init,
|
||||
.enable = &xil_gpio_irq_enable,
|
||||
.disable = &xil_gpio_irq_disable,
|
||||
.trigger_level_set = &xil_gpio_irq_trigger_level_set,
|
||||
.register_callback = &xil_gpio_irq_register_callback,
|
||||
.unregister_callback = xil_gpio_irq_unregister_callback,
|
||||
.remove = &xil_gpio_irq_ctrl_remove
|
||||
};
|
||||
@@ -0,0 +1,92 @@
|
||||
/***************************************************************************//**
|
||||
* @file xilinx_gpio_irq.h
|
||||
* @brief Implementation of Xilinx GPIO IRQ Generic Driver.
|
||||
* @author Porumb Andrei ([email protected])
|
||||
********************************************************************************
|
||||
* Copyright 2021(c) Analog Devices, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* - 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.
|
||||
* - Neither the name of Analog Devices, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
* - The use of this software may or may not infringe the patent rights
|
||||
* of one or more patent holders. This license does not release you
|
||||
* from the requirement that you obtain separate licenses from these
|
||||
* patent holders to use this software.
|
||||
* - Use of the software either in source or binary form, must be run
|
||||
* on or directly connected to an Analog Devices Inc. component.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef XILINX_GPIO_IRQ_H_
|
||||
#define XILINX_GPIO_IRQ_H_
|
||||
|
||||
/******************************************************************************/
|
||||
/***************************** Include Files **********************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#include "stdbool.h"
|
||||
#include "list.h"
|
||||
#include "xgpiops.h"
|
||||
#include "irq.h"
|
||||
|
||||
/******************************************************************************/
|
||||
/*************************** Types Declarations *******************************/
|
||||
/******************************************************************************/
|
||||
/**
|
||||
* @struct xil_callback_desc
|
||||
* @brief Structure holding callback parameters for each pin
|
||||
*/
|
||||
struct xil_callback_desc {
|
||||
int32_t pin_nb;
|
||||
struct callback_desc callback;
|
||||
bool triggered;
|
||||
bool enabled;
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct xil_gpio_irq_init_param
|
||||
* @brief Structure holding the initialization parameters for Xilinx platform
|
||||
* specific GPIO IRQ parameters.
|
||||
*/
|
||||
struct xil_gpio_irq_init_param {
|
||||
struct irq_ctrl_desc *parent_desc;
|
||||
int32_t gpio_device_id;
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct xil_gpio_irq_desc
|
||||
* @brief Xilinx platform specific GPIO IRQ descriptor
|
||||
*/
|
||||
struct xil_gpio_irq_desc {
|
||||
struct irq_ctrl_desc *parent_desc;
|
||||
XGpioPs my_Gpio;
|
||||
struct list_desc *callback_list;
|
||||
struct iterator *it;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Xilinx specific GPIO IRQ platform ops structure
|
||||
*/
|
||||
extern const struct irq_platform_ops xil_gpio_irq_ops;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,514 @@
|
||||
/***************************************************************************//**
|
||||
* @file xilinx/xilinx_i2c.c
|
||||
* @brief Implementation of Xilinx I2C Generic Driver.
|
||||
* @author Antoniu Miclaus ([email protected])
|
||||
********************************************************************************
|
||||
* Copyright 2019(c) Analog Devices, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* - 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.
|
||||
* - Neither the name of Analog Devices, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
* - The use of this software may or may not infringe the patent rights
|
||||
* of one or more patent holders. This license does not release you
|
||||
* from the requirement that you obtain separate licenses from these
|
||||
* patent holders to use this software.
|
||||
* - Use of the software either in source or binary form, must be run
|
||||
* on or directly connected to an Analog Devices Inc. component.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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 Files **********************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <xparameters.h>
|
||||
#ifdef XPAR_XIIC_NUM_INSTANCES
|
||||
#include <xiic.h>
|
||||
#endif
|
||||
#ifdef XPAR_XIICPS_NUM_INSTANCES
|
||||
#include <xiicps.h>
|
||||
#endif
|
||||
|
||||
#include "error.h"
|
||||
#include "i2c.h"
|
||||
#include "xilinx_i2c.h"
|
||||
#include "list.h"
|
||||
|
||||
/******************************************************************************/
|
||||
/*************************** Types Declarations *******************************/
|
||||
/******************************************************************************/
|
||||
|
||||
static struct list_desc *pl_list = NULL;
|
||||
static struct iterator *pl_it = NULL;
|
||||
|
||||
#ifdef XIICPS_H
|
||||
static struct list_desc *ps_list = NULL;
|
||||
static struct iterator *ps_it = NULL;
|
||||
#endif /* XIICPS_H */
|
||||
|
||||
/**
|
||||
* @struct inst_table_item
|
||||
* @brief Table item for I2C cores already started.
|
||||
*/
|
||||
struct inst_table_item {
|
||||
/** Instance the BSP driver uses for this core. */
|
||||
void *instance;
|
||||
/** Core ID in BSP. */
|
||||
uint32_t device_id;
|
||||
/** Number of ADI driver instances running on this core. */
|
||||
uint32_t inst_no;
|
||||
};
|
||||
|
||||
#ifdef XPAR_XIICPS_NUM_INSTANCES
|
||||
/** Save the current state of the bitrate to not change it each time */
|
||||
static uint32_t ps_last_bitrate = 0;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Xilinx platform specific I2C platform ops structure
|
||||
*/
|
||||
const struct i2c_platform_ops xil_i2c_ops = {
|
||||
.i2c_ops_init = &xil_i2c_init,
|
||||
.i2c_ops_write = &xil_i2c_write,
|
||||
.i2c_ops_read = &xil_i2c_read,
|
||||
.i2c_ops_remove = &xil_i2c_remove
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
/************************ Functions Definitions *******************************/
|
||||
/******************************************************************************/
|
||||
|
||||
/**
|
||||
* @brief Compare two I2C cores by ID.
|
||||
* @param el1 - First I2C core to compare.
|
||||
* @param el2 - Second I2C core to compare.
|
||||
* @return \ref 0 if the two cores have the same ID,
|
||||
* \ref difference between the first and the second IDs otherwise.
|
||||
*/
|
||||
static int32_t xil_i2c_cmp(void *el1, void *el2)
|
||||
{
|
||||
struct inst_table_item *sel1 = el1, *sel2 = el2;
|
||||
|
||||
return (sel1->device_id - sel2->device_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configure slave address and bitrate if needed
|
||||
* @param desc - Descriptor of the I2C device
|
||||
* @return 0 in case of success, -1 otherwise.
|
||||
*/
|
||||
static int32_t xil_i2c_set_transmission_config(struct i2c_desc *desc)
|
||||
{
|
||||
struct xil_i2c_desc *xil_i2c_desc = desc->extra;
|
||||
#ifdef XIICPS_H
|
||||
int32_t ret;
|
||||
#endif
|
||||
|
||||
switch (xil_i2c_desc->type) {
|
||||
case IIC_PL:
|
||||
#ifdef XIIC_H
|
||||
break;
|
||||
#endif
|
||||
return -1;
|
||||
case IIC_PS:
|
||||
#ifdef XIICPS_H
|
||||
if (desc->max_speed_hz != ps_last_bitrate) {
|
||||
ret = XIicPs_SetSClk(xil_i2c_desc->instance, desc->max_speed_hz);
|
||||
if (ret != XST_SUCCESS)
|
||||
return -1;
|
||||
ps_last_bitrate = desc->max_speed_hz;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
return -1;
|
||||
default:
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initialize the I2C communication peripheral.
|
||||
* @param desc - The I2C descriptor.
|
||||
* @param param - The structure that contains the I2C parameters.
|
||||
* @return 0 in case of success, -1 otherwise.
|
||||
*/
|
||||
int32_t xil_i2c_init(struct i2c_desc **desc,
|
||||
const struct i2c_init_param *param)
|
||||
{
|
||||
int32_t ret;
|
||||
struct i2c_desc *idesc;
|
||||
struct xil_i2c_desc *xdesc;
|
||||
struct xil_i2c_init_param *xinit;
|
||||
|
||||
idesc = (struct i2c_desc *)malloc(sizeof(*idesc));
|
||||
xdesc = (struct xil_i2c_desc *)malloc(sizeof(*xdesc));
|
||||
|
||||
if(!idesc || !xdesc)
|
||||
goto error;
|
||||
|
||||
idesc->max_speed_hz = param->max_speed_hz;
|
||||
idesc->slave_address = param->slave_address;
|
||||
xinit = param->extra;
|
||||
|
||||
idesc->extra = xdesc;
|
||||
xdesc->type = xinit->type;
|
||||
xdesc->device_id = xinit->device_id;
|
||||
switch (xinit->type) {
|
||||
case IIC_PL:
|
||||
#ifdef XIIC_H
|
||||
; /** Intentional empty statement */
|
||||
struct inst_table_item tab_check_pl;
|
||||
struct inst_table_item *temp_el_pl;
|
||||
|
||||
if (!pl_list)
|
||||
list_init(&pl_list, LIST_DEFAULT, xil_i2c_cmp);
|
||||
if (!pl_it)
|
||||
iterator_init(&pl_it, pl_list, true);
|
||||
|
||||
tab_check_pl.device_id = xdesc->device_id;
|
||||
|
||||
if (!IS_ERR_VALUE(list_read_find(pl_list, (void **)&temp_el_pl,
|
||||
&tab_check_pl))) {
|
||||
xdesc->instance = temp_el_pl->instance;
|
||||
temp_el_pl->inst_no++;
|
||||
break;
|
||||
}
|
||||
|
||||
xdesc->instance = (XIic *)malloc(sizeof(XIic));
|
||||
if(!xdesc->instance)
|
||||
goto pl_error;
|
||||
|
||||
xdesc->config = XIic_LookupConfig(xinit->device_id);
|
||||
if(xdesc->config == NULL)
|
||||
goto pl_error;
|
||||
|
||||
ret = XIic_CfgInitialize(xdesc->instance,
|
||||
xdesc->config,
|
||||
((XIic_Config*)xdesc->config)
|
||||
->BaseAddress);
|
||||
if(ret != 0)
|
||||
goto pl_error;
|
||||
|
||||
ret = XIic_Start(xdesc->instance);
|
||||
if(ret != 0)
|
||||
goto pl_error;
|
||||
|
||||
ret = XIic_SetAddress(xdesc->instance,
|
||||
XII_ADDR_TO_SEND_TYPE,
|
||||
param->slave_address);
|
||||
if(ret != 0)
|
||||
goto pl_error;
|
||||
|
||||
ret = XIic_SelfTest(xdesc->instance);
|
||||
if(ret < 0)
|
||||
goto pl_error;
|
||||
|
||||
ret = XIic_SetGpOutput(xdesc->instance, 1);
|
||||
if(ret < 0)
|
||||
goto pl_error;
|
||||
|
||||
temp_el_pl = (struct inst_table_item*)calloc(1, sizeof(*temp_el_pl));
|
||||
temp_el_pl->device_id = xinit->device_id;
|
||||
temp_el_pl->inst_no = 1;
|
||||
temp_el_pl->instance = xdesc->instance;
|
||||
pl_list->push(pl_list, temp_el_pl);
|
||||
|
||||
break;
|
||||
pl_error:
|
||||
free(xdesc->instance);
|
||||
#endif
|
||||
goto error;
|
||||
case IIC_PS:
|
||||
#ifdef XIICPS_H
|
||||
; /** Intentional empty statement */
|
||||
struct inst_table_item tab_check_ps;
|
||||
struct inst_table_item *temp_el_ps;
|
||||
|
||||
if (!pl_list)
|
||||
list_init(&ps_list, LIST_DEFAULT, xil_i2c_cmp);
|
||||
if (!pl_it)
|
||||
iterator_init(&ps_it, ps_list, true);
|
||||
|
||||
tab_check_ps.device_id = xdesc->device_id;
|
||||
|
||||
if (!IS_ERR_VALUE(list_read_find(ps_list,
|
||||
(void **)&temp_el_ps,
|
||||
&tab_check_ps))) {
|
||||
xdesc->instance = temp_el_ps->instance;
|
||||
temp_el_ps->inst_no++;
|
||||
break;
|
||||
}
|
||||
|
||||
xdesc->instance = (XIicPs *)malloc(sizeof(XIicPs));
|
||||
if(!xdesc->instance)
|
||||
goto ps_error;
|
||||
|
||||
xdesc->config = XIicPs_LookupConfig(xinit->device_id);
|
||||
if(xdesc->config == NULL)
|
||||
goto ps_error;
|
||||
|
||||
ret = XIicPs_CfgInitialize(xdesc->instance,
|
||||
xdesc->config,
|
||||
((XIicPs_Config*)xdesc->config)
|
||||
->BaseAddress);
|
||||
if(ret != 0)
|
||||
goto ps_error;
|
||||
|
||||
XIicPs_SetSClk(xdesc->instance, param->max_speed_hz);
|
||||
|
||||
temp_el_ps = (struct inst_table_item*)calloc(1, sizeof(*temp_el_ps));
|
||||
temp_el_ps->device_id = xinit->device_id;
|
||||
temp_el_ps->inst_no = 1;
|
||||
temp_el_ps->instance = xdesc->instance;
|
||||
ps_list->push(ps_list, temp_el_ps);
|
||||
|
||||
break;
|
||||
ps_error:
|
||||
free(xdesc->instance);
|
||||
#endif
|
||||
goto error;
|
||||
|
||||
default:
|
||||
goto error;
|
||||
break;
|
||||
}
|
||||
|
||||
*desc = idesc;
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
free(idesc);
|
||||
free(xdesc);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Free the resources allocated by i2c_init().
|
||||
* @param desc - The I2C descriptor.
|
||||
* @return 0 in case of success, -1 otherwise.
|
||||
*/
|
||||
int32_t xil_i2c_remove(struct i2c_desc *desc)
|
||||
{
|
||||
struct xil_i2c_desc *xdesc;
|
||||
int32_t ret;
|
||||
|
||||
xdesc = desc->extra;
|
||||
|
||||
switch (xdesc->type) {
|
||||
case IIC_PL:
|
||||
#ifdef XIIC_H
|
||||
; /** Intentional empty statement */
|
||||
struct inst_table_item tab_check_pl;
|
||||
struct inst_table_item *temp_el_pl;
|
||||
tab_check_pl.device_id = xdesc->device_id;
|
||||
ret = iterator_find(pl_it, &tab_check_pl);
|
||||
if (ret != 0)
|
||||
goto error;
|
||||
iterator_read(pl_it, (void **)&temp_el_pl);
|
||||
temp_el_pl->inst_no--;
|
||||
if (temp_el_pl->inst_no != 0)
|
||||
break;
|
||||
|
||||
ret = XIic_Stop(((XIic *)xdesc->instance));
|
||||
|
||||
if(ret != 0)
|
||||
goto error;
|
||||
|
||||
/** Remove list element */
|
||||
iterator_get(pl_it, (void **)&temp_el_pl);
|
||||
free(temp_el_pl);
|
||||
break;
|
||||
#endif
|
||||
goto error;
|
||||
case IIC_PS:
|
||||
#ifdef XIICPS_H
|
||||
; /** Intentional empty statement */
|
||||
struct inst_table_item tab_check_ps;
|
||||
struct inst_table_item *temp_el_ps;
|
||||
tab_check_ps.device_id = xdesc->device_id;
|
||||
ret = iterator_find(ps_it, &tab_check_ps);
|
||||
if (ret != 0)
|
||||
goto error;
|
||||
iterator_read(ps_it, (void **)&temp_el_ps);
|
||||
temp_el_ps->inst_no--;
|
||||
if (temp_el_ps->inst_no != 0)
|
||||
break;
|
||||
|
||||
/** Remove list element */
|
||||
iterator_get(ps_it, (void **)&temp_el_ps);
|
||||
free(temp_el_ps);
|
||||
break;
|
||||
#endif
|
||||
/* Intended fallthrough */
|
||||
error:
|
||||
default:
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
free(desc->extra);
|
||||
free(desc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Write data to a slave device.
|
||||
* @param desc - The I2C descriptor.
|
||||
* @param data - Buffer that stores the transmission data.
|
||||
* @param bytes_number - Number of bytes to write.
|
||||
* @param stop_bit - Stop condition control.
|
||||
* Example: 0 - A stop condition will not be generated;
|
||||
* 1 - A stop condition will be generated.
|
||||
* @return 0 in case of success, -1 otherwise.
|
||||
*/
|
||||
int32_t xil_i2c_write(struct i2c_desc *desc,
|
||||
uint8_t *data,
|
||||
uint8_t bytes_number,
|
||||
uint8_t stop_bit)
|
||||
{
|
||||
struct xil_i2c_desc *xdesc;
|
||||
int32_t ret;
|
||||
|
||||
xdesc = desc->extra;
|
||||
|
||||
switch (xdesc->type) {
|
||||
case IIC_PL:
|
||||
#ifdef XIIC_H
|
||||
ret = xil_i2c_set_transmission_config(desc);
|
||||
if (ret != 0)
|
||||
return -1;
|
||||
|
||||
XIic_Send(((XIic*)xdesc->instance)->BaseAddress,
|
||||
desc->slave_address,
|
||||
data,
|
||||
bytes_number,
|
||||
stop_bit ? XIIC_STOP : XIIC_REPEATED_START);
|
||||
break;
|
||||
#endif
|
||||
goto error;
|
||||
case IIC_PS:
|
||||
#ifdef XIICPS_H
|
||||
ret = xil_i2c_set_transmission_config(desc);
|
||||
if (ret != 0)
|
||||
return -1;
|
||||
|
||||
ret = XIicPs_SetOptions(xdesc->instance,
|
||||
stop_bit ? 0 : XIICPS_REP_START_OPTION);
|
||||
if(ret != 0)
|
||||
goto error;
|
||||
|
||||
XIicPs_MasterSend(xdesc->instance,
|
||||
data,
|
||||
bytes_number,
|
||||
desc->slave_address);
|
||||
if(ret != 0)
|
||||
goto error;
|
||||
|
||||
break;
|
||||
#endif
|
||||
/* Intended fallthrough */
|
||||
error:
|
||||
default:
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read data from a slave device.
|
||||
* @param desc - The I2C descriptor.
|
||||
* @param data - Buffer that will store the received data.
|
||||
* @param bytes_number - Number of bytes to read.
|
||||
* @param stop_bit - Stop condition control.
|
||||
* Example: 0 - A stop condition will not be generated;
|
||||
* 1 - A stop condition will be generated.
|
||||
* @return 0 in case of success, -1 otherwise.
|
||||
*/
|
||||
int32_t xil_i2c_read(struct i2c_desc *desc,
|
||||
uint8_t *data,
|
||||
uint8_t bytes_number,
|
||||
uint8_t stop_bit)
|
||||
{
|
||||
struct xil_i2c_desc *xdesc;
|
||||
int32_t ret;
|
||||
|
||||
xdesc = desc->extra;
|
||||
|
||||
switch (xdesc->type) {
|
||||
case IIC_PL:
|
||||
#ifdef XIIC_H
|
||||
ret = xil_i2c_set_transmission_config(desc);
|
||||
if (ret != 0)
|
||||
return -1;
|
||||
|
||||
ret = XIic_Recv(((XIic*)xdesc->instance)->BaseAddress,
|
||||
desc->slave_address,
|
||||
data,
|
||||
bytes_number,
|
||||
stop_bit ? XIIC_STOP : XIIC_REPEATED_START);
|
||||
if(ret != bytes_number)
|
||||
goto error;
|
||||
|
||||
break;
|
||||
#endif
|
||||
goto error;
|
||||
case IIC_PS:
|
||||
#ifdef XIICPS_H
|
||||
ret = xil_i2c_set_transmission_config(desc);
|
||||
if (ret != 0)
|
||||
return -1;
|
||||
|
||||
ret = XIicPs_SetOptions(xdesc->instance,
|
||||
stop_bit ? 0 : XIICPS_REP_START_OPTION);
|
||||
if(ret != 0)
|
||||
goto error;
|
||||
|
||||
XIicPs_MasterRecv(xdesc->instance,
|
||||
data,
|
||||
bytes_number,
|
||||
desc->slave_address);
|
||||
if(ret != 0)
|
||||
goto error;
|
||||
|
||||
break;
|
||||
#endif
|
||||
/* Intended fallthrough */
|
||||
error:
|
||||
default:
|
||||
return -1;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
/*******************************************************************************
|
||||
* @file xilinx/xilinx_i2c.h
|
||||
* @brief Header containing types used in the i2c driver.
|
||||
* @author scuciurean ([email protected])
|
||||
********************************************************************************
|
||||
* Copyright 2019(c) Analog Devices, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* - 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.
|
||||
* - Neither the name of Analog Devices, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
* - The use of this software may or may not infringe the patent rights
|
||||
* of one or more patent holders. This license does not release you
|
||||
* from the requirement that you obtain separate licenses from these
|
||||
* patent holders to use this software.
|
||||
* - Use of the software either in source or binary form, must be run
|
||||
* on or directly connected to an Analog Devices Inc. component.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef XILINX_I2C_H_
|
||||
#define XILINX_I2C_H_
|
||||
|
||||
/******************************************************************************/
|
||||
/***************************** Include Files **********************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/******************************************************************************/
|
||||
/*************************** Types Declarations *******************************/
|
||||
/******************************************************************************/
|
||||
|
||||
/**
|
||||
* @enum xil_i2c_type
|
||||
* @brief Xilinx platform architecture sections
|
||||
*/
|
||||
enum xil_i2c_type {
|
||||
/** Programmable Logic */
|
||||
IIC_PL,
|
||||
/** Processing System */
|
||||
IIC_PS
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct xil_i2c_init
|
||||
* @brief Structure holding the initialization parameters for Xilinx platform
|
||||
* specific I2C parameters.
|
||||
*/
|
||||
struct xil_i2c_init_param {
|
||||
/** Xilinx architecture */
|
||||
enum xil_i2c_type type;
|
||||
/** Device ID */
|
||||
uint32_t device_id;
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct xil_i2c_desc
|
||||
* @brief Xilinx platform specific I2C descriptor
|
||||
*/
|
||||
struct xil_i2c_desc {
|
||||
/** Xilinx architecture */
|
||||
enum xil_i2c_type type;
|
||||
/** Device ID */
|
||||
uint32_t device_id;
|
||||
/** Xilinx I2C configuration */
|
||||
void *config;
|
||||
/** Xilinx I2C Instance */
|
||||
void *instance;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Xilinx platform specific i2c platform ops structure
|
||||
*/
|
||||
extern const struct i2c_platform_ops xil_i2c_ops;
|
||||
|
||||
/******************************************************************************/
|
||||
/************************ Functions Declarations ******************************/
|
||||
/******************************************************************************/
|
||||
|
||||
/* Initialize the I2C communication peripheral. */
|
||||
int32_t xil_i2c_init(struct i2c_desc **desc,
|
||||
const struct i2c_init_param *param);
|
||||
|
||||
/* Free the resources allocated by i2c_init(). */
|
||||
int32_t xil_i2c_remove(struct i2c_desc *desc);
|
||||
|
||||
/* I2C Write data */
|
||||
int32_t xil_i2c_write(struct i2c_desc *desc, uint8_t *data,
|
||||
uint8_t bytes_number, uint8_t stop_bit);
|
||||
|
||||
/* I2C Read data. */
|
||||
int32_t xil_i2c_read(struct i2c_desc *desc, uint8_t *data,
|
||||
uint8_t bytes_number, uint8_t stop_bit);
|
||||
|
||||
#endif // XILINX_I2C_H_
|
||||
@@ -0,0 +1,433 @@
|
||||
/***************************************************************************//**
|
||||
* @file xilinx/xilinx_irq.c
|
||||
* @brief Implementation of Xilinx IRQ Generic Driver.
|
||||
* @author Cristian Pop ([email protected])
|
||||
********************************************************************************
|
||||
* Copyright 2019(c) Analog Devices, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* - 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.
|
||||
* - Neither the name of Analog Devices, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
* - The use of this software may or may not infringe the patent rights
|
||||
* of one or more patent holders. This license does not release you
|
||||
* from the requirement that you obtain separate licenses from these
|
||||
* patent holders to use this software.
|
||||
* - Use of the software either in source or binary form, must be run
|
||||
* on or directly connected to an Analog Devices Inc. component.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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 Files **********************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#include <xparameters.h>
|
||||
#include <stdlib.h>
|
||||
#include "error.h"
|
||||
#include "irq.h"
|
||||
#include "xilinx_irq.h"
|
||||
#ifdef XPAR_XSCUGIC_NUM_INSTANCES
|
||||
#include <xscugic.h>
|
||||
#endif
|
||||
#ifdef XPAR_XINTC_NUM_INSTANCES
|
||||
#include <xintc.h>
|
||||
#endif
|
||||
#ifdef XPAR_XTMRCTR_NUM_INSTANCES
|
||||
#include <xtmrctr.h>
|
||||
#endif
|
||||
|
||||
/******************************************************************************/
|
||||
/************************ Functions Definitions *******************************/
|
||||
/******************************************************************************/
|
||||
|
||||
/**
|
||||
* @brief Initialize the IRQ interrupts.
|
||||
* @param desc - The IRQ controller descriptor.
|
||||
* @param param - The structure that contains the IRQ parameters.
|
||||
* @return 0 in case of success, -1 otherwise.
|
||||
*/
|
||||
int32_t xil_irq_ctrl_init(struct irq_ctrl_desc **desc,
|
||||
const struct irq_init_param *param)
|
||||
{
|
||||
int32_t status;
|
||||
struct irq_ctrl_desc *descriptor;
|
||||
struct xil_irq_desc *xil_dev;
|
||||
#ifdef XSCUGIC_H
|
||||
void *config;
|
||||
#endif
|
||||
|
||||
descriptor = (struct irq_ctrl_desc *)calloc(1, sizeof *descriptor);
|
||||
if(!descriptor)
|
||||
return -1;
|
||||
xil_dev = (struct xil_irq_desc *)calloc(1, sizeof *xil_dev);
|
||||
if(!xil_dev) {
|
||||
free(descriptor);
|
||||
return -1;
|
||||
}
|
||||
|
||||
Xil_ExceptionInit();
|
||||
|
||||
descriptor->irq_ctrl_id = param->irq_ctrl_id;
|
||||
descriptor->extra = xil_dev;
|
||||
xil_dev->type = ((struct xil_irq_init_param *)param->extra)->type;
|
||||
|
||||
switch(xil_dev->type) {
|
||||
case IRQ_PS:
|
||||
#ifdef XSCUGIC_H
|
||||
xil_dev->instance = calloc(1, sizeof(XScuGic));
|
||||
if(!xil_dev->instance)
|
||||
goto error;
|
||||
|
||||
config = XScuGic_LookupConfig(descriptor->irq_ctrl_id);
|
||||
if(!config)
|
||||
goto ps_error;
|
||||
|
||||
status = XScuGic_CfgInitialize(xil_dev->instance, config,
|
||||
((XScuGic_Config *)config)->CpuBaseAddress);
|
||||
if (status != 0)
|
||||
goto ps_error;
|
||||
|
||||
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
|
||||
(Xil_ExceptionHandler)XScuGic_InterruptHandler,
|
||||
xil_dev->instance);
|
||||
|
||||
break;
|
||||
ps_error:
|
||||
free(xil_dev->instance);
|
||||
#endif
|
||||
goto error;
|
||||
case IRQ_PL:
|
||||
#ifdef XINTC_H
|
||||
xil_dev->instance = calloc(1, sizeof(XIntc));
|
||||
if(!xil_dev->instance)
|
||||
goto error;
|
||||
|
||||
status = XIntc_Initialize(xil_dev->instance, descriptor->irq_ctrl_id);
|
||||
if(status != 0)
|
||||
goto pl_error;
|
||||
|
||||
status = XIntc_Start(xil_dev->instance, XIN_REAL_MODE);
|
||||
if(status != 0)
|
||||
goto pl_error;
|
||||
|
||||
break;
|
||||
pl_error:
|
||||
free(xil_dev->instance);
|
||||
#endif
|
||||
goto error;
|
||||
default:
|
||||
goto error;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
*desc = descriptor;
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
free(xil_dev);
|
||||
free(descriptor);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable global interrupts.
|
||||
* @return 0 in case of success, -1 otherwise.
|
||||
*/
|
||||
int32_t xil_irq_global_enable(struct irq_ctrl_desc *desc)
|
||||
{
|
||||
/* Enable interrupts */
|
||||
Xil_ExceptionEnable();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disable global interrupts.
|
||||
* @return 0 in case of success, -1 otherwise.
|
||||
*/
|
||||
int32_t xil_irq_global_disable(struct irq_ctrl_desc *desc)
|
||||
{
|
||||
/* Disable interrupts */
|
||||
Xil_ExceptionDisable();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable specific interrupt.
|
||||
* @param desc - The IRQ controller descriptor.
|
||||
* @param irq_id - Interrupt identifier.
|
||||
* @return 0 in case of success, -1 otherwise.
|
||||
*/
|
||||
int32_t xil_irq_enable(struct irq_ctrl_desc *desc, uint32_t irq_id)
|
||||
{
|
||||
struct xil_irq_desc *xil_dev = desc->extra;
|
||||
|
||||
switch(xil_dev->type) {
|
||||
case IRQ_PS:
|
||||
#ifdef XSCUGIC_H
|
||||
XScuGic_Enable(xil_dev->instance, irq_id);
|
||||
#endif
|
||||
break;
|
||||
case IRQ_PL:
|
||||
#ifdef XINTC_H
|
||||
XIntc_Enable(xil_dev->instance, irq_id);
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disable specific interrupt.
|
||||
* @param desc - The IRQ controller descriptor.
|
||||
* @param irq_id - Interrupt identifier.
|
||||
* @return 0 in case of success, -1 otherwise.
|
||||
*/
|
||||
int32_t xil_irq_disable(struct irq_ctrl_desc *desc, uint32_t irq_id)
|
||||
{
|
||||
struct xil_irq_desc *xil_dev = desc->extra;
|
||||
|
||||
switch(xil_dev->type) {
|
||||
case IRQ_PS:
|
||||
#ifdef XSCUGIC_H
|
||||
XScuGic_Disable(xil_dev->instance, irq_id);
|
||||
#endif
|
||||
break;
|
||||
case IRQ_PL:
|
||||
#ifdef XINTC_H
|
||||
XIntc_Disable(xil_dev->instance, irq_id);
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Register a callback to handle the irq events.
|
||||
* @param desc - The IRQ controller descriptor.
|
||||
* @param irq_id - Interrupt identifier.
|
||||
* @param callback_desc - Callback descriptor
|
||||
* @return 0 in case of success, -1 otherwise.
|
||||
*/
|
||||
int32_t xil_irq_register_callback(struct irq_ctrl_desc *desc,
|
||||
uint32_t irq_id,
|
||||
struct callback_desc *callback_desc)
|
||||
{
|
||||
struct xil_irq_desc *xil_dev = desc->extra;
|
||||
|
||||
switch(xil_dev->type) {
|
||||
case IRQ_PS:
|
||||
#ifdef XSCUGIC_H
|
||||
return XScuGic_Connect(xil_dev->instance, irq_id,
|
||||
(Xil_InterruptHandler) callback_desc->callback,
|
||||
callback_desc->ctx);
|
||||
#endif
|
||||
break;
|
||||
case IRQ_PL:
|
||||
#ifdef XINTC_H
|
||||
if (irq_id == XPAR_AXI_INTC_AXI_TIMER_INTERRUPT_INTR) {
|
||||
int32_t ret;
|
||||
|
||||
ret = XIntc_Connect(xil_dev->instance, irq_id,
|
||||
XTmrCtr_InterruptHandler, callback_desc->legacy_config);
|
||||
if (IS_ERR_VALUE(ret))
|
||||
return -1;
|
||||
XTmrCtr_SetHandler(callback_desc->legacy_config,
|
||||
(XTmrCtr_Handler)callback_desc->callback,
|
||||
callback_desc->ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
return XIntc_Connect(xil_dev->instance, irq_id,
|
||||
(XInterruptHandler) callback_desc->callback,
|
||||
callback_desc->ctx);
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set interrupt trigger level.
|
||||
* @param desc - The IRQ controller descriptor.
|
||||
* @param irq_id - Interrupt identifier.
|
||||
* @param trig - New trigger level for the interrupt.
|
||||
* @return 0 in case of success, -1 otherwise.
|
||||
*/
|
||||
int32_t xil_irq_trigger_level_set(struct irq_ctrl_desc *desc,
|
||||
uint32_t irq_id,
|
||||
enum irq_trig_level trig)
|
||||
{
|
||||
struct xil_irq_desc *xil_dev = desc->extra;
|
||||
|
||||
if(trig == IRQ_EDGE_BOTH)
|
||||
return -EINVAL;
|
||||
|
||||
switch(xil_dev->type) {
|
||||
case IRQ_PS:
|
||||
#ifdef XSCUGIC_H
|
||||
;
|
||||
uint8_t priority, trigger;
|
||||
|
||||
XScuGic_GetPriorityTriggerType(xil_dev->instance, irq_id, &priority,
|
||||
&trigger);
|
||||
trigger = trig;
|
||||
XScuGic_SetPriorityTriggerType(xil_dev->instance, irq_id, priority,
|
||||
trigger);
|
||||
|
||||
return 0;
|
||||
#endif
|
||||
break;
|
||||
case IRQ_PL:
|
||||
#ifdef XINTC_H
|
||||
/* Interrupt trigger determined in hardware. TODO: verify */
|
||||
return 0;
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set interrupt trigger level.
|
||||
* @param desc - The IRQ controller descriptor.
|
||||
* @param irq_id - Interrupt identifier.
|
||||
* @param priority_level - New priority level for the interrupt.
|
||||
* @return 0 in case of success, -1 otherwise.
|
||||
*/
|
||||
int32_t xil_irq_set_priority(struct irq_ctrl_desc *desc,
|
||||
uint32_t irq_id,
|
||||
uint32_t priority_level)
|
||||
{
|
||||
struct xil_irq_desc *xil_dev = desc->extra;
|
||||
|
||||
if(priority_level % 8 != 0)
|
||||
return -EINVAL;
|
||||
|
||||
switch(xil_dev->type) {
|
||||
case IRQ_PS:
|
||||
#ifdef XSCUGIC_H
|
||||
;
|
||||
uint8_t priority, trigger;
|
||||
|
||||
XScuGic_GetPriorityTriggerType(xil_dev->instance, irq_id, &priority,
|
||||
&trigger);
|
||||
priority = priority_level;
|
||||
XScuGic_SetPriorityTriggerType(xil_dev->instance, irq_id, priority,
|
||||
trigger);
|
||||
|
||||
return 0;
|
||||
#endif
|
||||
break;
|
||||
case IRQ_PL:
|
||||
#ifdef XINTC_H
|
||||
/* Interrupt priority level determined in hardware. TODO: verify */
|
||||
return 0;
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Unregisters a generic IRQ handling function.
|
||||
* @param desc - The IRQ controller descriptor.
|
||||
* @param irq_id - Interrupt identifier.
|
||||
* @param cb - Callback descriptor.
|
||||
* @return 0 in case of success, -1 otherwise.
|
||||
*/
|
||||
int32_t xil_irq_unregister_callback(struct irq_ctrl_desc *desc,
|
||||
uint32_t irq_id, struct callback_desc *cb)
|
||||
{
|
||||
struct xil_irq_desc *xil_dev = desc->extra;
|
||||
|
||||
switch(xil_dev->type) {
|
||||
case IRQ_PS:
|
||||
#ifdef XSCUGIC_H
|
||||
XScuGic_Disconnect(xil_dev->instance, irq_id);
|
||||
#endif
|
||||
break;
|
||||
case IRQ_PL:
|
||||
#ifdef XINTC_H
|
||||
XIntc_Disconnect(xil_dev->instance, irq_id);
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Free the resources allocated by irq_ctrl_init().
|
||||
* @param desc - The IRQ control descriptor.
|
||||
* @return 0 in case of success, -1 otherwise.
|
||||
*/
|
||||
int32_t xil_irq_ctrl_remove(struct irq_ctrl_desc *desc)
|
||||
{
|
||||
struct xil_irq_desc *xil_dev = desc->extra;
|
||||
free(xil_dev->instance);
|
||||
free(desc->extra);
|
||||
free(desc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Xilinx platform specific IRQ platform ops structure
|
||||
*/
|
||||
const struct irq_platform_ops xil_irq_ops = {
|
||||
.init = &xil_irq_ctrl_init,
|
||||
.register_callback = &xil_irq_register_callback,
|
||||
.unregister_callback = &xil_irq_unregister_callback,
|
||||
.global_enable = &xil_irq_global_enable,
|
||||
.global_disable = &xil_irq_global_disable,
|
||||
.trigger_level_set = &xil_irq_trigger_level_set,
|
||||
.set_priority = &xil_irq_set_priority,
|
||||
.enable = &xil_irq_enable,
|
||||
.disable = &xil_irq_disable,
|
||||
.remove = &xil_irq_ctrl_remove
|
||||
};
|
||||
@@ -0,0 +1,91 @@
|
||||
/*******************************************************************************
|
||||
* @file xilinx_irq.h
|
||||
* @brief Header containing types used in the irq driver.
|
||||
* @author Cristian Pop ([email protected])
|
||||
********************************************************************************
|
||||
* Copyright 2019(c) Analog Devices, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* - 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.
|
||||
* - Neither the name of Analog Devices, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
* - The use of this software may or may not infringe the patent rights
|
||||
* of one or more patent holders. This license does not release you
|
||||
* from the requirement that you obtain separate licenses from these
|
||||
* patent holders to use this software.
|
||||
* - Use of the software either in source or binary form, must be run
|
||||
* on or directly connected to an Analog Devices Inc. component.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef XILINX_IRQ_H_
|
||||
#define XILINX_IRQ_H_
|
||||
|
||||
/******************************************************************************/
|
||||
/***************************** Include Files **********************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "irq.h"
|
||||
|
||||
/******************************************************************************/
|
||||
/*************************** Types Declarations *******************************/
|
||||
/******************************************************************************/
|
||||
|
||||
/**
|
||||
* @enum xil_irq_type
|
||||
* @brief Xilinx platform architecture sections
|
||||
*/
|
||||
enum xil_irq_type {
|
||||
/** Programmable Logic */
|
||||
IRQ_PL,
|
||||
/** Processing System */
|
||||
IRQ_PS
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct xil_irq_init_param
|
||||
* @brief Structure holding the initialization parameters for Xilinx platform
|
||||
* specific IRQ parameters.
|
||||
*/
|
||||
struct xil_irq_init_param {
|
||||
/** Xilinx architecture */
|
||||
enum xil_irq_type type;
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct xil_irq_desc
|
||||
* @brief Xilinx platform specific IRQ descriptor
|
||||
*/
|
||||
struct xil_irq_desc {
|
||||
/** Xilinx architecture */
|
||||
enum xil_irq_type type;
|
||||
/** Xilinx IRQ Instance */
|
||||
void *instance;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Xilinx specific IRQ platform ops structure
|
||||
*/
|
||||
extern const struct irq_platform_ops xil_irq_ops;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,462 @@
|
||||
/***************************************************************************//**
|
||||
* @file xilinx/xilinx_spi.c
|
||||
* @brief Implementation of Xilinx SPI Generic Driver.
|
||||
* @author Antoniu Miclaus ([email protected])
|
||||
********************************************************************************
|
||||
* Copyright 2019(c) Analog Devices, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* - 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.
|
||||
* - Neither the name of Analog Devices, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
* - The use of this software may or may not infringe the patent rights
|
||||
* of one or more patent holders. This license does not release you
|
||||
* from the requirement that you obtain separate licenses from these
|
||||
* patent holders to use this software.
|
||||
* - Use of the software either in source or binary form, must be run
|
||||
* on or directly connected to an Analog Devices Inc. component.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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 Files **********************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <xparameters.h>
|
||||
#ifdef XPAR_XSPI_NUM_INSTANCES
|
||||
#include <xspi.h>
|
||||
#endif
|
||||
#ifdef XPAR_XSPIPS_NUM_INSTANCES
|
||||
#include <xspips.h>
|
||||
#endif
|
||||
|
||||
#include "error.h"
|
||||
#include "spi.h"
|
||||
#include "xilinx_spi.h"
|
||||
|
||||
#if defined(PLATFORM_ZYNQ)
|
||||
#define SPI_CLK_FREQ_HZ(dev) (XPAR_PS7_SPI_ ## dev ## _SPI_CLK_FREQ_HZ)
|
||||
#define SPI_NUM_INSTANCES XPAR_XSPIPS_NUM_INSTANCES
|
||||
#elif defined(PLATFORM_ZYNQMP)
|
||||
#define SPI_CLK_FREQ_HZ(dev) (XPAR_PSU_SPI_ ## dev ## _SPI_CLK_FREQ_HZ)
|
||||
#define SPI_NUM_INSTANCES XPAR_XSPIPS_NUM_INSTANCES
|
||||
#else
|
||||
#define SPI_NUM_INSTANCES 0
|
||||
#endif
|
||||
|
||||
#warning SPI delays are not supported on the xilinx platform
|
||||
|
||||
/******************************************************************************/
|
||||
/************************ Functions Definitions *******************************/
|
||||
/******************************************************************************/
|
||||
|
||||
/**
|
||||
* @brief Initialize the hardware SPI peripherial
|
||||
*
|
||||
* @param xdesc Platform specific SPI descriptor
|
||||
* @param xinit Platform specific SPI init param
|
||||
* @return int32_t -1 if the device couldn't be found or configured
|
||||
*/
|
||||
static int32_t spi_init_pl(struct spi_desc *desc,
|
||||
const struct spi_init_param *param)
|
||||
{
|
||||
#ifdef XSPI_H
|
||||
int32_t ret;
|
||||
struct xil_spi_desc *xdesc;
|
||||
struct xil_spi_init_param *xinit;
|
||||
|
||||
xdesc = (struct xil_spi_desc*)malloc(sizeof(struct xil_spi_desc));
|
||||
if(!xdesc) {
|
||||
free(xdesc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
desc->extra = xdesc;
|
||||
xinit = param->extra;
|
||||
xdesc->type = xinit->type;
|
||||
xdesc->flags = xinit->flags;
|
||||
|
||||
xdesc->instance = (XSpi*)calloc(1, sizeof(XSpi));
|
||||
if(!xdesc->instance)
|
||||
goto pl_error;
|
||||
|
||||
xdesc->config = XSpi_LookupConfig(param->device_id);
|
||||
if(xdesc->config == NULL)
|
||||
goto pl_error;
|
||||
|
||||
ret = XSpi_CfgInitialize(xdesc->instance,
|
||||
xdesc->config,
|
||||
((XSpi_Config*)xdesc->config)
|
||||
->BaseAddress);
|
||||
if(ret != 0)
|
||||
goto pl_error;
|
||||
|
||||
ret = XSpi_Initialize(xdesc->instance, param->device_id);
|
||||
if (ret != 0)
|
||||
goto pl_error;
|
||||
|
||||
ret = XSpi_SetOptions(xdesc->instance,
|
||||
XSP_MASTER_OPTION |
|
||||
((desc->mode & SPI_CPOL) ?
|
||||
XSP_CLK_ACTIVE_LOW_OPTION : 0) |
|
||||
((desc->mode & SPI_CPHA) ?
|
||||
XSP_CLK_PHASE_1_OPTION : 0));
|
||||
if (ret != 0)
|
||||
goto pl_error;
|
||||
|
||||
ret = XSpi_Start(xdesc->instance);
|
||||
if (ret != 0)
|
||||
goto pl_error;
|
||||
|
||||
XSpi_IntrGlobalDisable((XSpi *)(xdesc->instance));
|
||||
|
||||
return 0;
|
||||
|
||||
pl_error:
|
||||
free(xdesc->instance);
|
||||
free(xdesc);
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initialize the hardware SPI peripherial
|
||||
*
|
||||
* @param xdesc Platform specific SPI descriptor
|
||||
* @param xinit Platform specific SPI init param
|
||||
* @return int32_t -1 if the device couldn't be found or configured
|
||||
*/
|
||||
static int32_t spi_init_ps(struct spi_desc *desc,
|
||||
const struct spi_init_param *param)
|
||||
{
|
||||
#ifdef XSPIPS_H
|
||||
int32_t ret;
|
||||
struct xil_spi_desc *xdesc;
|
||||
struct xil_spi_init_param *xinit;
|
||||
const uint32_t prescaler_default = XSPIPS_CLK_PRESCALE_64;
|
||||
const uint32_t prescaler_min = XSPIPS_CLK_PRESCALE_4;
|
||||
const uint32_t prescaler_max = XSPIPS_CLK_PRESCALE_256;
|
||||
uint32_t prescaler = 0u;
|
||||
uint32_t input_clock = 0u;
|
||||
|
||||
xdesc = (struct xil_spi_desc*)malloc(sizeof(struct xil_spi_desc));
|
||||
if(!xdesc) {
|
||||
free(xdesc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
desc->extra = xdesc;
|
||||
xinit = param->extra;
|
||||
xdesc->type = xinit->type;
|
||||
xdesc->flags = xinit->flags;
|
||||
|
||||
xdesc->instance = (XSpiPs*)malloc(sizeof(XSpiPs));
|
||||
if(!xdesc->instance)
|
||||
goto ps_error;
|
||||
|
||||
xdesc->config = XSpiPs_LookupConfig(param->device_id);
|
||||
if(xdesc->config == NULL)
|
||||
goto ps_error;
|
||||
|
||||
ret = XSpiPs_CfgInitialize(xdesc->instance,
|
||||
xdesc->config,
|
||||
((XSpiPs_Config*)xdesc->config)
|
||||
->BaseAddress);
|
||||
if(ret != 0)
|
||||
goto ps_error;
|
||||
|
||||
switch (param->device_id) {
|
||||
#if (SPI_NUM_INSTANCES >= 1)
|
||||
case 0:
|
||||
input_clock = SPI_CLK_FREQ_HZ(0);
|
||||
break;
|
||||
#endif
|
||||
#if (SPI_NUM_INSTANCES >= 2)
|
||||
case 1:
|
||||
input_clock = SPI_CLK_FREQ_HZ(1);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
goto ps_error;
|
||||
};
|
||||
|
||||
if (desc->max_speed_hz != 0u) {
|
||||
uint32_t div = input_clock / desc->max_speed_hz;
|
||||
uint32_t rem = input_clock % desc->max_speed_hz;
|
||||
uint32_t po2 = !(div & (div - 1)) && !rem;
|
||||
|
||||
// find the power of two just higher than div and
|
||||
// store the exponent in prescaler
|
||||
while(div) {
|
||||
prescaler += 1;
|
||||
div >>= 1u;
|
||||
}
|
||||
|
||||
// this exponent - 1 is needed because of the way
|
||||
// xilinx stores it into registers
|
||||
if (prescaler)
|
||||
prescaler -= 1;
|
||||
|
||||
// this exponent - 1 is needed when initial div was
|
||||
// precisely a power of two
|
||||
if (prescaler && po2)
|
||||
prescaler -= 1;
|
||||
|
||||
if (prescaler < prescaler_min)
|
||||
prescaler = prescaler_min;
|
||||
|
||||
if (prescaler > prescaler_max)
|
||||
prescaler = prescaler_max;
|
||||
} else
|
||||
prescaler = prescaler_default;
|
||||
|
||||
ret = XSpiPs_SetClkPrescaler(xdesc->instance, prescaler);
|
||||
|
||||
if(ret != 0)
|
||||
goto ps_error;
|
||||
|
||||
return 0;
|
||||
|
||||
ps_error:
|
||||
free(xdesc->instance);
|
||||
free(xdesc);
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initialize the SPI communication peripheral.
|
||||
* @param desc - The SPI descriptor.
|
||||
* @param param - The structure that contains the SPI parameters.
|
||||
* @return 0 in case of success, -1 otherwise.
|
||||
*/
|
||||
int32_t xil_spi_init(struct spi_desc **desc,
|
||||
const struct spi_init_param *param)
|
||||
{
|
||||
int32_t ret;
|
||||
enum xil_spi_type *spi_type;
|
||||
|
||||
if (!param) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*desc = malloc(sizeof(**desc));
|
||||
if(! *desc) {
|
||||
free(*desc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
spi_type = param->extra;
|
||||
|
||||
if(!spi_type)
|
||||
goto init_error;
|
||||
|
||||
(*desc)->max_speed_hz = param->max_speed_hz;
|
||||
(*desc)->mode = param->mode;
|
||||
(*desc)->bit_order = param->bit_order;
|
||||
(*desc)->chip_select = param->chip_select;
|
||||
|
||||
switch (*spi_type) {
|
||||
case SPI_PL:
|
||||
ret = spi_init_pl(*desc, param);
|
||||
break;
|
||||
case SPI_PS:
|
||||
ret = spi_init_ps(*desc, param);
|
||||
break;
|
||||
|
||||
default:
|
||||
goto init_error;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret != 0) {
|
||||
init_error:
|
||||
free(*desc);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Free the resources allocated by spi_init().
|
||||
* @param desc - The SPI descriptor.
|
||||
* @return 0 in case of success, -1 otherwise.
|
||||
*/
|
||||
int32_t xil_spi_remove(struct spi_desc *desc)
|
||||
{
|
||||
#ifdef XSPI_H
|
||||
int32_t ret;
|
||||
#endif
|
||||
struct xil_spi_desc *xdesc = NULL;
|
||||
enum xil_spi_type *spi_type;
|
||||
|
||||
spi_type = desc->extra;
|
||||
|
||||
if(!spi_type)
|
||||
return -1;
|
||||
|
||||
switch (*spi_type ) {
|
||||
case SPI_PL:
|
||||
#ifdef XSPI_H
|
||||
xdesc = desc->extra;
|
||||
|
||||
if(!xdesc)
|
||||
return -1;
|
||||
|
||||
ret = XSpi_Stop((XSpi *)(xdesc->instance));
|
||||
if(ret != 0)
|
||||
goto error;
|
||||
#endif
|
||||
break;
|
||||
case SPI_PS:
|
||||
#ifdef XSPIPS_H
|
||||
xdesc = desc->extra;
|
||||
|
||||
if(!xdesc)
|
||||
return -1;
|
||||
#endif
|
||||
break;
|
||||
|
||||
/* Intended fallthrough */
|
||||
#ifdef XSPI_H
|
||||
error:
|
||||
#endif
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(xdesc)
|
||||
free(xdesc->instance);
|
||||
free(desc->extra);
|
||||
free(desc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Write and read data to/from SPI.
|
||||
* @param desc - The SPI descriptor.
|
||||
* @param data - The buffer with the transmitted/received data.
|
||||
* @param bytes_number - Number of bytes to write/read.
|
||||
* @return 0 in case of success, -1 otherwise.
|
||||
*/
|
||||
int32_t xil_spi_write_and_read(struct spi_desc *desc,
|
||||
uint8_t *data,
|
||||
uint16_t bytes_number)
|
||||
{
|
||||
int32_t ret;
|
||||
#ifdef XSPI_H
|
||||
uint32_t ctrl_reg;
|
||||
#endif
|
||||
struct xil_spi_desc *xdesc;
|
||||
enum xil_spi_type *spi_type;
|
||||
|
||||
ret = -1;
|
||||
|
||||
spi_type = desc->extra;
|
||||
|
||||
if(!spi_type)
|
||||
return -1;
|
||||
|
||||
xdesc = desc->extra;
|
||||
|
||||
switch (*spi_type) {
|
||||
case SPI_PL:
|
||||
#ifdef XSPI_H
|
||||
ret = XSpi_SetOptions(xdesc->instance,
|
||||
XSP_MASTER_OPTION |
|
||||
((desc->mode & SPI_CPOL) ?
|
||||
XSP_CLK_ACTIVE_LOW_OPTION : 0) |
|
||||
((desc->mode & SPI_CPHA) ?
|
||||
XSP_CLK_PHASE_1_OPTION : 0));
|
||||
if (ret != 0)
|
||||
goto error;
|
||||
|
||||
ctrl_reg = XSpi_GetControlReg(((XSpi*)xdesc->instance));
|
||||
if (desc->bit_order == SPI_BIT_ORDER_LSB_FIRST)
|
||||
ctrl_reg |= XSP_CR_LSB_MSB_FIRST_MASK;
|
||||
else
|
||||
ctrl_reg &= ~ XSP_CR_LSB_MSB_FIRST_MASK;
|
||||
XSpi_SetControlReg(((XSpi*)xdesc->instance), ctrl_reg);
|
||||
|
||||
ret = XSpi_SetSlaveSelect(xdesc->instance,
|
||||
0x01 << desc->chip_select);
|
||||
if (ret != 0)
|
||||
goto error;
|
||||
|
||||
ret = XSpi_Transfer(xdesc->instance,
|
||||
data,
|
||||
data,
|
||||
bytes_number);
|
||||
if (ret != 0)
|
||||
goto error;
|
||||
#endif
|
||||
break;
|
||||
case SPI_PS:
|
||||
#ifdef XSPIPS_H
|
||||
ret = XSpiPs_SetOptions(xdesc->instance,
|
||||
XSPIPS_MASTER_OPTION |
|
||||
((xdesc->flags & SPI_CS_DECODE) ?
|
||||
XSPIPS_DECODE_SSELECT_OPTION : 0) |
|
||||
XSPIPS_FORCE_SSELECT_OPTION |
|
||||
((desc->mode & SPI_CPOL) ?
|
||||
XSPIPS_CLK_ACTIVE_LOW_OPTION : 0) |
|
||||
((desc->mode & SPI_CPHA) ?
|
||||
XSPIPS_CLK_PHASE_1_OPTION : 0));
|
||||
if (ret != 0)
|
||||
goto error;
|
||||
|
||||
ret = XSpiPs_SetSlaveSelect(xdesc->instance,
|
||||
desc->chip_select);
|
||||
if (ret != 0)
|
||||
goto error;
|
||||
ret = XSpiPs_PolledTransfer(xdesc->instance,
|
||||
data,
|
||||
data,
|
||||
bytes_number);
|
||||
if (ret != 0)
|
||||
goto error;
|
||||
ret = XSpiPs_SetSlaveSelect(xdesc->instance, SPI_DEASSERT_CURRENT_SS);
|
||||
if (ret != 0)
|
||||
goto error;
|
||||
#endif
|
||||
break;
|
||||
error:
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Xilinx platform specific SPI platform ops structure
|
||||
*/
|
||||
const struct spi_platform_ops xil_spi_ops = {
|
||||
.init = &xil_spi_init,
|
||||
.write_and_read = &xil_spi_write_and_read,
|
||||
.remove = &xil_spi_remove
|
||||
};
|
||||
@@ -0,0 +1,115 @@
|
||||
/*******************************************************************************
|
||||
* @file xilinx/xilinx_spi.h
|
||||
* @brief Header containing extra types used in the spi driver.
|
||||
* @author scuciurean ([email protected])
|
||||
********************************************************************************
|
||||
* Copyright 2019(c) Analog Devices, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* - 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.
|
||||
* - Neither the name of Analog Devices, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
* - The use of this software may or may not infringe the patent rights
|
||||
* of one or more patent holders. This license does not release you
|
||||
* from the requirement that you obtain separate licenses from these
|
||||
* patent holders to use this software.
|
||||
* - Use of the software either in source or binary form, must be run
|
||||
* on or directly connected to an Analog Devices Inc. component.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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.
|
||||
*******************************************************************************/
|
||||
#ifndef XILINX_SPI_H_
|
||||
#define XILINX_SPI_H_
|
||||
|
||||
/******************************************************************************/
|
||||
/***************************** Include Files **********************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "spi.h"
|
||||
|
||||
/******************************************************************************/
|
||||
/********************** Macros and Constants Definitions **********************/
|
||||
/******************************************************************************/
|
||||
|
||||
#define SPI_CS_DECODE 0x01
|
||||
#define SPI_DEASSERT_CURRENT_SS 0x0F
|
||||
|
||||
/******************************************************************************/
|
||||
/*************************** Types Declarations *******************************/
|
||||
/******************************************************************************/
|
||||
|
||||
/**
|
||||
* @enum xil_spi_type
|
||||
* @brief Xilinx platform architecture sections
|
||||
*/
|
||||
enum xil_spi_type {
|
||||
/** Programmable Logic */
|
||||
SPI_PL,
|
||||
/** Processing System */
|
||||
SPI_PS,
|
||||
/** SPI Engine */
|
||||
SPI_ENGINE
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct xil_spi_init_param
|
||||
* @brief Structure holding the initialization parameters for Xilinx platform
|
||||
* specific SPI parameters when using xil_spi_ops.
|
||||
*/
|
||||
struct xil_spi_init_param {
|
||||
/** Xilinx architecture */
|
||||
enum xil_spi_type type;
|
||||
/** SPI flags */
|
||||
uint32_t flags;
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct xil_spi_desc
|
||||
* @brief Xilinx platform specific SPI descriptor
|
||||
*/
|
||||
struct xil_spi_desc {
|
||||
/** Xilinx architecture */
|
||||
enum xil_spi_type type;
|
||||
/** SPI flags */
|
||||
uint32_t flags;
|
||||
/** SPI configuration */
|
||||
void *config;
|
||||
/** SPI instance */
|
||||
void *instance;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief SPI engine platform ops structure
|
||||
*/
|
||||
extern const struct spi_platform_ops spi_eng_platform_ops;
|
||||
|
||||
/**
|
||||
* @brief Xilinx specific SPI platform ops structure
|
||||
*/
|
||||
extern const struct spi_platform_ops xil_spi_ops;
|
||||
|
||||
/**
|
||||
* @brief Xilinx SPI PS register functions. No extra param needed
|
||||
*/
|
||||
extern const struct spi_platform_ops xil_spi_pl_ops;
|
||||
|
||||
#endif // XILINX_SPI_H_
|
||||
@@ -0,0 +1,533 @@
|
||||
/*******************************************************************************
|
||||
* @file xilinx/xilinx_spi_pl.c
|
||||
* @brief Driver for spi pl device using registers
|
||||
* @author Mihail Chindris ([email protected])
|
||||
********************************************************************************
|
||||
* Copyright 2021(c) Analog Devices, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* - 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.
|
||||
* - Neither the name of Analog Devices, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
* - The use of this software may or may not infringe the patent rights
|
||||
* of one or more patent holders. This license does not release you
|
||||
* from the requirement that you obtain separate licenses from these
|
||||
* patent holders to use this software.
|
||||
* - Use of the software either in source or binary form, must be run
|
||||
* on or directly connected to an Analog Devices Inc. component.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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 <xparameters.h>
|
||||
|
||||
#ifdef XPAR_XSPI_NUM_INSTANCES
|
||||
|
||||
/******************************************************************************/
|
||||
/***************************** Include Files **********************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#include <xspi.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include "spi.h"
|
||||
#include "error.h"
|
||||
#include "delay.h"
|
||||
#include "util.h"
|
||||
#include "alloc.h"
|
||||
|
||||
/******************************************************************************/
|
||||
/********************** Macros and Constants Definitions **********************/
|
||||
/******************************************************************************/
|
||||
|
||||
#define XPS_TYPE_WRITE 0x1
|
||||
#define XPS_TYPE_READ 0x2
|
||||
#define XSP_DEFAULT_SR_VALUE 0x25
|
||||
#define XSP_DUMMY_DATA 0xFF
|
||||
|
||||
/*
|
||||
* Used to store current spi device configuration in order to not update it for
|
||||
* each spi transaction if not needed.
|
||||
*/
|
||||
static struct spi_desc g_spi_desc[XPAR_XSPI_NUM_INSTANCES];
|
||||
|
||||
/******************************************************************************/
|
||||
/*************************** Types Declarations *******************************/
|
||||
/******************************************************************************/
|
||||
|
||||
/* Xilinx PL spi specific data */
|
||||
struct xspi_desc {
|
||||
uint32_t base_addr;
|
||||
uint32_t disable_slaves_mask;
|
||||
uint32_t fifo_depth;
|
||||
uint8_t cs_asserted;
|
||||
};
|
||||
|
||||
/* Structure used to iterate over SPI messages */
|
||||
struct msg_iter {
|
||||
struct spi_msg *msgs;
|
||||
uint32_t len;
|
||||
uint32_t i;
|
||||
uint32_t buff_i;
|
||||
uint8_t is_wr;
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
/************************ Functions Definitions *******************************/
|
||||
/******************************************************************************/
|
||||
|
||||
/* Read device register */
|
||||
static inline uint32_t _read(struct xspi_desc *xdesc, uint32_t reg)
|
||||
{
|
||||
return Xil_In32(xdesc->base_addr + reg);
|
||||
}
|
||||
|
||||
/* Write device register */
|
||||
static inline void _write(struct xspi_desc *xdesc, uint32_t reg, uint32_t val)
|
||||
{
|
||||
Xil_Out32(xdesc->base_addr + reg, val);
|
||||
}
|
||||
|
||||
/* Update device register. Only bits set to 1 in mask will be modified */
|
||||
static inline void _wr_mask(struct xspi_desc *xdesc, uint32_t reg,
|
||||
uint32_t val, uint32_t mask)
|
||||
{
|
||||
uint32_t tmp;
|
||||
|
||||
tmp = _read(xdesc, reg);
|
||||
tmp &= ~mask;
|
||||
tmp |= val & mask;
|
||||
_write(xdesc, reg, tmp);
|
||||
}
|
||||
|
||||
/* Update spi device configuration if needed */
|
||||
static void _update_mode(struct spi_desc *desc)
|
||||
{
|
||||
uint32_t val;
|
||||
uint32_t mask;
|
||||
|
||||
if (desc->mode == g_spi_desc[desc->device_id].mode &&
|
||||
desc->bit_order == g_spi_desc[desc->device_id].bit_order)
|
||||
return ;
|
||||
|
||||
/* Update mode */
|
||||
val = desc->mode | SPI_CPOL ? XSP_CR_CLK_POLARITY_MASK : 0;
|
||||
val |= desc->mode | SPI_CPHA ? XSP_CR_CLK_PHASE_MASK : 0;
|
||||
mask = XSP_CR_CLK_POLARITY_MASK | XSP_CR_CLK_PHASE_MASK;
|
||||
|
||||
val |= desc->bit_order == SPI_BIT_ORDER_LSB_FIRST ?
|
||||
XSP_CR_LSB_MSB_FIRST_MASK : 0;
|
||||
mask |= XSP_CR_LSB_MSB_FIRST_MASK;
|
||||
|
||||
_wr_mask(desc->extra, XSP_CR_OFFSET, val, mask);
|
||||
g_spi_desc[desc->device_id] = *desc;
|
||||
}
|
||||
|
||||
/* Configure SPI PL device */
|
||||
static int32_t _xil_spi_init_dev(struct xspi_desc *xdesc)
|
||||
{
|
||||
uint32_t val;
|
||||
|
||||
/* Software reset */
|
||||
_write(xdesc, XSP_SRR_OFFSET, XSP_SRR_RESET_MASK);
|
||||
mdelay(1);
|
||||
|
||||
/* Check if success reset */
|
||||
val = _read(xdesc, XSP_SR_OFFSET);
|
||||
if (val != XSP_DEFAULT_SR_VALUE)
|
||||
return -ENODEV;
|
||||
|
||||
/* Disable interrupts. Drivers only works with pooled mode */
|
||||
_write(xdesc, XSP_IIER_OFFSET, 0);
|
||||
|
||||
/* Deasert chip selects */
|
||||
_write(xdesc, XSP_SSR_OFFSET, 0xFFFFFFFF);
|
||||
|
||||
/* Get fifo depth */
|
||||
while (!(_read(xdesc, XSP_SR_OFFSET) & XSP_SR_TX_FULL_MASK))
|
||||
_write(xdesc, XSP_DTR_OFFSET, XSP_DUMMY_DATA);
|
||||
xdesc->fifo_depth = _read(xdesc, XSP_TFO_OFFSET) + 1;
|
||||
|
||||
/* Configure spi device */
|
||||
val = XSP_CR_ENABLE_MASK |
|
||||
XSP_CR_MANUAL_SS_MASK |
|
||||
XSP_CR_TXFIFO_RESET_MASK |
|
||||
XSP_CR_RXFIFO_RESET_MASK |
|
||||
XSP_CR_MASTER_MODE_MASK |
|
||||
XSP_CR_TRANS_INHIBIT_MASK;
|
||||
|
||||
_write(xdesc, XSP_CR_OFFSET, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Initialize spi_desc structure and device */
|
||||
static int32_t xil_spi_init_pl(struct spi_desc **desc,
|
||||
const struct spi_init_param *param)
|
||||
{
|
||||
struct spi_desc *ldesc;
|
||||
struct xspi_desc *xdesc;
|
||||
int32_t err;
|
||||
XSpi_Config *cfg;
|
||||
|
||||
if (!desc || !param || param->device_id >= XPAR_XSPI_NUM_INSTANCES)
|
||||
return -EINVAL;
|
||||
|
||||
cfg = XSpi_LookupConfig(param->device_id);
|
||||
if (!cfg)
|
||||
return -EINVAL;
|
||||
|
||||
if (param->chip_select > cfg->NumSlaveBits)
|
||||
return -EINVAL;
|
||||
|
||||
ldesc = (struct spi_desc *)calloc(1, sizeof(*ldesc));
|
||||
if (!ldesc)
|
||||
return -ENOMEM;
|
||||
|
||||
xdesc = (struct xspi_desc *)calloc(1, sizeof(*xdesc));
|
||||
if (!xdesc) {
|
||||
err = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
ldesc->bit_order = param->bit_order;
|
||||
ldesc->chip_select = param->chip_select;
|
||||
ldesc->mode = param->mode;
|
||||
xdesc->base_addr = cfg->BaseAddress;
|
||||
xdesc->disable_slaves_mask = (1 << cfg->NumSlaveBits) - 1;
|
||||
xdesc->cs_asserted = 0;
|
||||
|
||||
err = _xil_spi_init_dev(xdesc);
|
||||
if (IS_ERR_VALUE(err))
|
||||
goto error;
|
||||
|
||||
ldesc->extra = xdesc;
|
||||
*desc = ldesc;
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
free(xdesc);
|
||||
free(ldesc);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Remove allocated resources */
|
||||
static int32_t xil_spi_remove_pl(struct spi_desc *desc)
|
||||
{
|
||||
if (!desc)
|
||||
return -EINVAL;
|
||||
|
||||
free(desc->extra);
|
||||
free(desc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fill fifo until fifo is full or no more data available.
|
||||
* Return the number of written bytes.
|
||||
*/
|
||||
static uint32_t _wr_fifo(struct xspi_desc *xdesc, uint8_t *data,
|
||||
uint32_t len)
|
||||
{
|
||||
uint32_t i;
|
||||
uint32_t to_write;
|
||||
uint32_t tx_available;
|
||||
|
||||
tx_available = xdesc->fifo_depth - _read(xdesc, XSP_TFO_OFFSET);
|
||||
to_write = min(tx_available, len);
|
||||
for (i = 0; i < to_write; ++i)
|
||||
if (data)
|
||||
_write(xdesc, XSP_DTR_OFFSET, data[i]);
|
||||
else
|
||||
_write(xdesc, XSP_DTR_OFFSET, XSP_DUMMY_DATA);
|
||||
|
||||
return to_write;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read fifo until fifo is empty or no more buffer available to read into
|
||||
* Returns the number of read bytes
|
||||
*/
|
||||
static uint32_t _rd_fifo(struct xspi_desc *xdesc, uint8_t *data,
|
||||
uint32_t len)
|
||||
{
|
||||
uint32_t rx_available;
|
||||
uint32_t to_read;
|
||||
uint32_t tmp;
|
||||
uint32_t i;
|
||||
|
||||
tmp = _read(xdesc, XSP_SR_OFFSET);
|
||||
if (tmp & XSP_SR_RX_EMPTY_MASK)
|
||||
return 0;
|
||||
|
||||
rx_available = _read(xdesc, XSP_RFO_OFFSET) + 1;
|
||||
to_read = min(rx_available, len);
|
||||
for (i = 0; i < to_read; ++i) {
|
||||
tmp = _read(xdesc, XSP_DRR_OFFSET);
|
||||
if (data)
|
||||
data[i] = tmp;
|
||||
}
|
||||
|
||||
return to_read;
|
||||
}
|
||||
|
||||
/* If start is 0 stop transfer, else start it.
|
||||
* CS will be asserted if needed. If different CS othere than the one needed
|
||||
* is asserted. Deassert it and assert correct one */
|
||||
static void _xil_spi_start_transfer(struct spi_desc *desc, uint8_t start)
|
||||
{
|
||||
struct xspi_desc *xdesc;
|
||||
|
||||
xdesc = desc->extra;
|
||||
if (start) {
|
||||
if (xdesc->cs_asserted) {
|
||||
if (desc->chip_select ==
|
||||
g_spi_desc[desc->device_id].chip_select)
|
||||
return ;
|
||||
else
|
||||
/* Stop transfer to start again with new CS */
|
||||
_xil_spi_start_transfer(desc, 0);
|
||||
}
|
||||
_write(xdesc, XSP_SSR_OFFSET, ~(1 << desc->chip_select));
|
||||
_wr_mask(xdesc, XSP_CR_OFFSET, 0, XSP_CR_TRANS_INHIBIT_MASK);
|
||||
} else {
|
||||
_wr_mask(xdesc, XSP_CR_OFFSET, XSP_CR_TRANS_INHIBIT_MASK,
|
||||
XSP_CR_TRANS_INHIBIT_MASK);
|
||||
_write(xdesc, XSP_SSR_OFFSET, xdesc->disable_slaves_mask);
|
||||
}
|
||||
xdesc->cs_asserted = start;
|
||||
}
|
||||
|
||||
|
||||
/* SPI polled transfer */
|
||||
static int32_t xil_spi_write_and_read_pl(struct spi_desc *desc,
|
||||
uint8_t *data,
|
||||
uint16_t bytes_number)
|
||||
{
|
||||
struct xspi_desc *xdesc;
|
||||
uint32_t rx;
|
||||
uint32_t tx;
|
||||
|
||||
if (!desc || !desc->extra)
|
||||
return -EINVAL;
|
||||
|
||||
xdesc = desc->extra;
|
||||
_update_mode(desc);
|
||||
|
||||
_xil_spi_start_transfer(desc, 1);
|
||||
rx = 0;
|
||||
tx = 0;
|
||||
while (rx < bytes_number) {
|
||||
if (tx < bytes_number)
|
||||
tx += _wr_fifo(xdesc, data + tx, bytes_number - tx);
|
||||
rx += _rd_fifo(xdesc, data + rx, bytes_number - rx);
|
||||
}
|
||||
_xil_spi_start_transfer(desc, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get type of message. It can be READ, WRITE or both */
|
||||
static uint32_t _get_msg_type(struct spi_msg *msg)
|
||||
{
|
||||
uint32_t type;
|
||||
|
||||
type = 0;
|
||||
if (msg->tx_buff)
|
||||
type |= XPS_TYPE_WRITE;
|
||||
if (msg->rx_buff)
|
||||
type |= XPS_TYPE_READ;
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
/* Get information based on current iterator position */
|
||||
static void _get_data(struct msg_iter *it, uint8_t **buff, uint32_t *len,
|
||||
uint32_t *type)
|
||||
{
|
||||
struct spi_msg *msg;
|
||||
|
||||
if (it->i == it->len) {
|
||||
*len = 0;
|
||||
return ;
|
||||
}
|
||||
|
||||
msg = it->msgs + it->i;
|
||||
if (it->is_wr)
|
||||
*buff = msg->tx_buff;
|
||||
else
|
||||
*buff = msg->rx_buff;
|
||||
|
||||
if (*buff)
|
||||
*buff += it->buff_i;
|
||||
|
||||
*len = msg->bytes_number - it->buff_i;
|
||||
if (type)
|
||||
*type = _get_msg_type(msg);
|
||||
}
|
||||
|
||||
/*
|
||||
* Increment iterator position with desired length.
|
||||
* If the new position has a different message type, new_type will be set to 1
|
||||
* If a CS change is needed, cs_change is set
|
||||
*/
|
||||
static void _increment_iter(struct msg_iter *it, uint32_t len,
|
||||
uint8_t *cs_change, uint8_t *new_type)
|
||||
{
|
||||
struct spi_msg *msg;
|
||||
uint32_t type;
|
||||
uint32_t extra_len;
|
||||
|
||||
if (!len)
|
||||
return ;
|
||||
|
||||
*cs_change = 0;
|
||||
*new_type = 0;
|
||||
msg = it->msgs + it->i;
|
||||
if (it->buff_i + len > msg->bytes_number)
|
||||
extra_len = it->buff_i + len - msg->bytes_number;
|
||||
else
|
||||
extra_len = 0;
|
||||
len -= extra_len;
|
||||
it->buff_i += len;
|
||||
if (it->buff_i == msg->bytes_number) {
|
||||
type = _get_msg_type(msg);
|
||||
++it->i;
|
||||
it->buff_i = 0;
|
||||
if (cs_change && msg->cs_change)
|
||||
*cs_change = 1;
|
||||
if (new_type)
|
||||
if (it->i == it->len ||
|
||||
type != _get_msg_type(it->msgs + it->i))
|
||||
*new_type = 1;
|
||||
}
|
||||
if (extra_len)
|
||||
_increment_iter(it, extra_len, cs_change, new_type);
|
||||
}
|
||||
|
||||
/*
|
||||
* SPI polling transfer of multiple messages.
|
||||
*/
|
||||
static int32_t xil_spi_transfer_pl(struct spi_desc *desc,
|
||||
struct spi_msg *msgs,
|
||||
uint32_t len)
|
||||
|
||||
{
|
||||
struct xspi_desc *xdesc;
|
||||
uint8_t cs_change;
|
||||
uint8_t new_type;
|
||||
struct msg_iter rx = {.msgs = msgs, .len = len, .is_wr = 0};
|
||||
struct msg_iter tx = {.msgs = msgs, .len = len, .is_wr = 1};
|
||||
uint8_t *buff;
|
||||
uint32_t bytes;
|
||||
uint32_t type;
|
||||
/* Bytes to increment rx when only a write transaction is executed */
|
||||
uint32_t to_inc_rx;
|
||||
/* Difference between rx and tx iterators in bytes */
|
||||
uint32_t tx_advance;
|
||||
/* Save bytes sent during a write loop */
|
||||
uint32_t tx_sent;
|
||||
/* Used to loop if need to empty the RX FIFO */
|
||||
uint32_t loop;
|
||||
|
||||
if (!desc || !desc->extra)
|
||||
return -EINVAL;
|
||||
|
||||
xdesc = desc->extra;
|
||||
_update_mode(desc);
|
||||
|
||||
tx_advance = 0;
|
||||
to_inc_rx = 0;
|
||||
buff = NULL;
|
||||
type = 0;
|
||||
do {
|
||||
_xil_spi_start_transfer(desc, 1);
|
||||
|
||||
tx_sent = 0;
|
||||
/* Writing loop */
|
||||
do {
|
||||
_get_data(&tx, &buff, &bytes, &type);
|
||||
if (type & XPS_TYPE_READ)
|
||||
/*
|
||||
* Do not write more bytes than fifo_depth if
|
||||
* they haven't been read.
|
||||
*/
|
||||
bytes = min(bytes,
|
||||
xdesc->fifo_depth - tx_advance);
|
||||
bytes = _wr_fifo(xdesc, buff, bytes);
|
||||
tx_sent += bytes;
|
||||
_increment_iter(&tx, bytes, &cs_change, &new_type);
|
||||
tx_advance += bytes;
|
||||
} while (!cs_change && !new_type && bytes);
|
||||
|
||||
if (type & XPS_TYPE_READ) {
|
||||
loop = 1;
|
||||
/*
|
||||
* Loop only when no more data to write otherwise read
|
||||
* only available data.
|
||||
*/
|
||||
while (loop) {
|
||||
if (!new_type)
|
||||
loop = 0;
|
||||
_get_data(&rx, &buff, &bytes, NULL);
|
||||
bytes = _rd_fifo(xdesc, buff, bytes);
|
||||
_increment_iter(&rx, bytes, &cs_change, &new_type);
|
||||
tx_advance -= bytes;
|
||||
if (loop && new_type)
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* Clean RX FIFO if it was only a WRITE message */
|
||||
to_inc_rx += tx_sent;
|
||||
if (new_type) {
|
||||
/* Wait for TX to be sent */
|
||||
while (!(_read(xdesc, XSP_SR_OFFSET) &
|
||||
XSP_SR_TX_EMPTY_MASK))
|
||||
;
|
||||
/* Reset fifo. Only write was performed */
|
||||
_wr_mask(xdesc, XSP_CR_OFFSET,
|
||||
XSP_CR_RXFIFO_RESET_MASK,
|
||||
XSP_CR_RXFIFO_RESET_MASK);
|
||||
|
||||
_increment_iter(&rx, to_inc_rx, NULL, NULL);
|
||||
tx_advance -= to_inc_rx;
|
||||
to_inc_rx = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ((cs_change && rx.i != len) || (!cs_change && rx.i == len))
|
||||
_xil_spi_start_transfer(desc, 0);
|
||||
} while (rx.i < len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct spi_platform_ops xil_spi_pl_ops = {
|
||||
.init = xil_spi_init_pl,
|
||||
.remove = xil_spi_remove_pl,
|
||||
.write_and_read = xil_spi_write_and_read_pl,
|
||||
.transfer = xil_spi_transfer_pl
|
||||
};
|
||||
|
||||
#endif // XPAR_XSPI_NUM_INSTANCES
|
||||
@@ -0,0 +1,456 @@
|
||||
/***************************************************************************//**
|
||||
* @file xilinx/xilinx_timer.c
|
||||
* @brief Timer and GIC control module source.
|
||||
* @author Andrei Drimbarean ([email protected])
|
||||
********************************************************************************
|
||||
* Copyright 2020(c) Analog Devices, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* - 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.
|
||||
* - Neither the name of Analog Devices, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
* - The use of this software may or may not infringe the patent rights
|
||||
* of one or more patent holders. This license does not release you
|
||||
* from the requirement that you obtain separate licenses from these
|
||||
* patent holders to use this software.
|
||||
* - Use of the software either in source or binary form, must be run
|
||||
* on or directly connected to an Analog Devices Inc. component.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT, MERCHANTABILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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 Files **********************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <xparameters.h>
|
||||
#include "timer.h"
|
||||
#include "xilinx_timer.h"
|
||||
#include "error.h"
|
||||
|
||||
/******************************************************************************/
|
||||
/********************** Macros and Constants Definitions **********************/
|
||||
/******************************************************************************/
|
||||
|
||||
#if defined(_XPARAMETERS_PS_H_)
|
||||
#define CORE_PRIVATE_TIMER_CLOCK (XPAR_CPU_CORTEXA9_CORE_CLOCK_FREQ_HZ / 2)
|
||||
#endif
|
||||
|
||||
/******************************************************************************/
|
||||
/************************ Functions Definitions *******************************/
|
||||
/******************************************************************************/
|
||||
|
||||
/**
|
||||
* @brief Set the current counter value of the timer.
|
||||
* @param [in] desc - Pointer to the device handler.
|
||||
* @param [in] new_val - New value for the timer counter.
|
||||
* @return 0 in case of success, -1 otherwise
|
||||
*/
|
||||
int32_t xilinx_timer_counter_set(struct timer_desc *desc,
|
||||
uint32_t new_val)
|
||||
{
|
||||
struct xil_timer_desc *xdesc;
|
||||
|
||||
if (!desc)
|
||||
return -1;
|
||||
|
||||
xdesc = desc->extra;
|
||||
|
||||
switch (xdesc->type) {
|
||||
case TIMER_PS:
|
||||
#ifdef XSCUTIMER_H
|
||||
XScuTimer_LoadTimer((XScuTimer *)xdesc->instance, new_val - 1);
|
||||
break;
|
||||
#endif
|
||||
return -1;
|
||||
case TIMER_PL:
|
||||
#ifdef XTMRCTR_H
|
||||
XTmrCtr_SetResetValue(xdesc->instance, xdesc->active_tmr, new_val);
|
||||
XTmrCtr_Reset(xdesc->instance, xdesc->active_tmr);
|
||||
break;
|
||||
#endif
|
||||
return -1;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the timer clock frequency.
|
||||
* @param [in] desc - Pointer to the device handler.
|
||||
* @param [in] freq_hz - New timer frequency in hertz.
|
||||
* @return 0 in case of success, -1 otherwise
|
||||
*/
|
||||
int32_t xilinx_timer_count_clk_set(struct timer_desc *desc,
|
||||
uint32_t freq_hz)
|
||||
{
|
||||
struct xil_timer_desc *xdesc;
|
||||
|
||||
if (!desc || !freq_hz)
|
||||
return -1;
|
||||
|
||||
xdesc = desc->extra;
|
||||
|
||||
switch (xdesc->type) {
|
||||
case TIMER_PS:
|
||||
#ifdef XSCUTIMER_H
|
||||
;
|
||||
uint32_t prescaler = CORE_PRIVATE_TIMER_CLOCK / freq_hz;
|
||||
if (prescaler == 0 || prescaler >= 256)
|
||||
return -1;
|
||||
XScuTimer_SetPrescaler(xdesc->instance, prescaler - 1);
|
||||
desc->freq_hz = CORE_PRIVATE_TIMER_CLOCK / prescaler;
|
||||
break;
|
||||
#endif
|
||||
return -1;
|
||||
case TIMER_PL:
|
||||
#ifdef XTMRCTR_H
|
||||
(void *)xdesc;
|
||||
/** Cannot be done. */
|
||||
#endif
|
||||
return -1;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initialize hardware timer and the handler structure associated with
|
||||
* it.
|
||||
* @param [out] desc - Pointer to the reference of the device handler.
|
||||
* @param [in] param - Initialization structure.
|
||||
* @return 0 in case of success, -1 otherwise
|
||||
*/
|
||||
int32_t xilinx_timer_init(struct timer_desc **desc,
|
||||
const struct timer_init_param *param)
|
||||
{
|
||||
int32_t ret;
|
||||
struct timer_desc *dev;
|
||||
struct xil_timer_desc *xdesc;
|
||||
struct xil_timer_init_param *xinit;
|
||||
|
||||
if (!desc || !param)
|
||||
return -1;
|
||||
|
||||
xinit = param->extra;
|
||||
|
||||
dev = (struct timer_desc *)calloc(1, sizeof(*dev));
|
||||
if(!dev)
|
||||
return -1;
|
||||
xdesc = (struct xil_timer_desc *)calloc(1, sizeof(*xdesc));
|
||||
if(!xdesc)
|
||||
goto error_desc;
|
||||
|
||||
dev->id = param->id;
|
||||
dev->freq_hz = param->freq_hz;
|
||||
dev->ticks_count = param->ticks_count;
|
||||
dev->extra = xdesc;
|
||||
xdesc->active_tmr = xinit->active_tmr;
|
||||
xdesc->type = xinit->type;
|
||||
|
||||
switch (xdesc->type) {
|
||||
case TIMER_PS:
|
||||
#ifdef XSCUTIMER_H
|
||||
xdesc->config = XScuTimer_LookupConfig(dev->id);
|
||||
xdesc->instance = calloc(1, sizeof(XScuTimer));
|
||||
if (!xdesc->instance)
|
||||
goto error_xdesc;
|
||||
ret = XScuTimer_CfgInitialize(xdesc->instance, xdesc->config,
|
||||
((XScuTimer_Config *)xdesc->config)->BaseAddr);
|
||||
if (ret != XST_SUCCESS) {
|
||||
free(xdesc->instance);
|
||||
goto error_xdesc;
|
||||
}
|
||||
ret = xilinx_timer_count_clk_set(dev, param->freq_hz);
|
||||
if (IS_ERR_VALUE(ret))
|
||||
goto error_xdesc;
|
||||
|
||||
ret = xilinx_timer_counter_set(dev, dev->ticks_count);
|
||||
if (IS_ERR_VALUE(ret))
|
||||
goto error_xdesc;
|
||||
|
||||
XScuTimer_EnableAutoReload((XScuTimer *)xdesc->instance);
|
||||
XScuTimer_EnableInterrupt((XScuTimer *)xdesc->instance);
|
||||
break;
|
||||
#endif
|
||||
goto error_xdesc;
|
||||
case TIMER_PL:
|
||||
#ifdef XTMRCTR_H
|
||||
xdesc->instance = (XTmrCtr *)calloc(1, sizeof(XTmrCtr));
|
||||
if (!xdesc->instance)
|
||||
return -1;
|
||||
|
||||
xdesc->config = XTmrCtr_LookupConfig(dev->id);
|
||||
if (!xdesc->config) {
|
||||
free(xdesc->instance);
|
||||
goto error_desc;
|
||||
}
|
||||
XTmrCtr_CfgInitialize(xdesc->instance, xdesc->config,
|
||||
((XTmrCtr_Config *)xdesc->config)->BaseAddress);
|
||||
ret = XTmrCtr_InitHw(xdesc->instance);
|
||||
if (ret != 0) {
|
||||
free(xdesc->instance);
|
||||
goto error_desc;
|
||||
}
|
||||
dev->freq_hz = ((XTmrCtr_Config *)xdesc->config)->SysClockFreqHz;
|
||||
|
||||
ret = XTmrCtr_SelfTest(xdesc->instance, dev->id);
|
||||
if(ret != 0)
|
||||
goto error_desc;
|
||||
XTmrCtr_SetOptions(xdesc->instance, xdesc->active_tmr,
|
||||
XTC_DOWN_COUNT_OPTION | XTC_INT_MODE_OPTION |
|
||||
XTC_AUTO_RELOAD_OPTION);
|
||||
XTmrCtr_SetResetValue(xdesc->instance, xdesc->active_tmr,
|
||||
dev->ticks_count);
|
||||
break;
|
||||
#endif
|
||||
goto error_xdesc;
|
||||
default:
|
||||
goto error_xdesc;
|
||||
}
|
||||
|
||||
*desc = dev;
|
||||
|
||||
return 0;
|
||||
|
||||
error_xdesc:
|
||||
free(xdesc);
|
||||
error_desc:
|
||||
free(dev);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Free the memory allocated by timer_setup().
|
||||
* @param [in] desc - Pointer to the device handler.
|
||||
* @return 0 in case of success, -1 otherwise
|
||||
*/
|
||||
int32_t xilinx_timer_remove(struct timer_desc *desc)
|
||||
{
|
||||
struct xil_timer_desc *xdesc;
|
||||
|
||||
if(!desc)
|
||||
return -1;
|
||||
|
||||
xdesc = desc->extra;
|
||||
|
||||
switch (xdesc->type) {
|
||||
case TIMER_PS:
|
||||
#ifdef XSCUTIMER_H
|
||||
XScuTimer_Stop(xdesc->instance);
|
||||
free(xdesc->instance);
|
||||
break;
|
||||
#endif
|
||||
return -1;
|
||||
case TIMER_PL:
|
||||
#ifdef XTMRCTR_H
|
||||
XTmrCtr_Stop(xdesc->instance, xdesc->active_tmr);
|
||||
break;
|
||||
#endif
|
||||
return -1;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
free(xdesc);
|
||||
free(desc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Start a timer.
|
||||
* @param [in] desc - Pointer to the device handler.
|
||||
* @return 0 in case of success, -1 otherwise
|
||||
*/
|
||||
int32_t xilinx_timer_start(struct timer_desc *desc)
|
||||
{
|
||||
struct xil_timer_desc *xdesc;
|
||||
|
||||
if (!desc)
|
||||
return -1;
|
||||
|
||||
xdesc = desc->extra;
|
||||
|
||||
switch (xdesc->type) {
|
||||
case TIMER_PS:
|
||||
#ifdef XSCUTIMER_H
|
||||
XScuTimer_Start(xdesc->instance);
|
||||
break;
|
||||
#endif
|
||||
return -1;
|
||||
case TIMER_PL:
|
||||
#ifdef XTMRCTR_H
|
||||
XTmrCtr_Start(xdesc->instance, xdesc->active_tmr);
|
||||
break;
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Stop a timer from counting.
|
||||
* @param [in] desc - Pointer to the device handler.
|
||||
* @return 0 in case of success, -1 otherwise
|
||||
*/
|
||||
int32_t xilinx_timer_stop(struct timer_desc *desc)
|
||||
{
|
||||
struct xil_timer_desc *xdesc;
|
||||
|
||||
if (!desc)
|
||||
return -1;
|
||||
|
||||
xdesc = desc->extra;
|
||||
|
||||
switch (xdesc->type) {
|
||||
case TIMER_PS:
|
||||
#ifdef XSCUTIMER_H
|
||||
XScuTimer_Stop(xdesc->instance);
|
||||
break;
|
||||
#endif
|
||||
return -1;
|
||||
case TIMER_PL:
|
||||
#ifdef XTMRCTR_H
|
||||
XTmrCtr_Stop(xdesc->instance, xdesc->active_tmr);
|
||||
break;
|
||||
#endif
|
||||
return -1;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the current counter value of the timer.
|
||||
* @param [in] desc - Pointer to the device handler.
|
||||
* @param [out] counter - Pointer to the current counter value.
|
||||
* @return 0 in case of success, -1 otherwise
|
||||
*/
|
||||
int32_t xilinx_timer_counter_get(struct timer_desc *desc,
|
||||
uint32_t *counter)
|
||||
{
|
||||
struct xil_timer_desc *xdesc;
|
||||
|
||||
if (!desc || !counter)
|
||||
return -1;
|
||||
|
||||
xdesc = desc->extra;
|
||||
|
||||
switch (xdesc->type) {
|
||||
case TIMER_PS:
|
||||
#ifdef XSCUTIMER_H
|
||||
*counter = XScuTimer_GetCounterValue((XScuTimer *)xdesc->instance);
|
||||
++(*counter);
|
||||
break;
|
||||
#endif
|
||||
return -1;
|
||||
case TIMER_PL:
|
||||
#ifdef XTMRCTR_H
|
||||
*counter = XTmrCtr_GetValue(xdesc->instance, xdesc->active_tmr);
|
||||
break;
|
||||
#endif
|
||||
return -1;
|
||||
default:
|
||||
*counter = 0;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the timer clock frequency.
|
||||
* @param [in] desc - Pointer to the device handler.
|
||||
* @param [out] freq_hz - Pointer to the returned frequency.
|
||||
* @return 0 in case of success, -1 otherwise
|
||||
*/
|
||||
int32_t xilinx_timer_count_clk_get(struct timer_desc *desc,
|
||||
uint32_t *freq_hz)
|
||||
{
|
||||
struct xil_timer_desc *xdesc;
|
||||
|
||||
if (!desc || !freq_hz)
|
||||
return -1;
|
||||
|
||||
xdesc = desc->extra;
|
||||
|
||||
switch (xdesc->type) {
|
||||
case TIMER_PS:
|
||||
#ifdef XSCUTIMER_H
|
||||
*freq_hz = desc->freq_hz;
|
||||
break;
|
||||
#endif
|
||||
return -1;
|
||||
case TIMER_PL:
|
||||
#ifdef XTMRCTR_H
|
||||
*freq_hz = ((XTmrCtr_Config *)xdesc->config)->SysClockFreqHz;
|
||||
break;
|
||||
#endif
|
||||
return -1;
|
||||
default:
|
||||
*freq_hz = 0;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the elapsed time in nsec for the timer.
|
||||
* @param [in] desc - Pointer to the device handler.
|
||||
* @param [in] elapsed_time - The elapsed time in nsec.
|
||||
* @return -ENOSYS.
|
||||
*/
|
||||
int32_t xilinx_timer_get_elapsed_time_nsec(struct timer_desc *desc,
|
||||
uint64_t *elapsed_time)
|
||||
{
|
||||
/* Function not implemented */
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Xilinx platform specific timer platform ops structure
|
||||
*/
|
||||
const struct timer_platform_ops xil_timer_ops = {
|
||||
.init = &xilinx_timer_init,
|
||||
.start = &xilinx_timer_start,
|
||||
.stop = &xilinx_timer_stop,
|
||||
.counter_get = &xilinx_timer_counter_get,
|
||||
.counter_set = &xilinx_timer_counter_set,
|
||||
.count_clk_get = &xilinx_timer_count_clk_get,
|
||||
.count_clk_set = &xilinx_timer_count_clk_set,
|
||||
.get_elapsed_time_nsec = &xilinx_timer_get_elapsed_time_nsec,
|
||||
.remove = &xilinx_timer_remove
|
||||
};
|
||||
@@ -0,0 +1,101 @@
|
||||
/***************************************************************************//**
|
||||
* @file xilinx_timer.h
|
||||
* @brief Timer control module header.
|
||||
* @author Andrei Drimbarean ([email protected])
|
||||
********************************************************************************
|
||||
* Copyright 2020(c) Analog Devices, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* - 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.
|
||||
* - Neither the name of Analog Devices, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
* - The use of this software may or may not infringe the patent rights
|
||||
* of one or more patent holders. This license does not release you
|
||||
* from the requirement that you obtain separate licenses from these
|
||||
* patent holders to use this software.
|
||||
* - Use of the software either in source or binary form, must be run
|
||||
* on or directly connected to an Analog Devices Inc. component.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT, MERCHANTABILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef XILINX_TIMER_H_
|
||||
#define XILINX_TIMER_H_
|
||||
|
||||
/******************************************************************************/
|
||||
/***************************** Include Files **********************************/
|
||||
/******************************************************************************/
|
||||
|
||||
#include <xparameters.h>
|
||||
#ifdef XPAR_XSCUTIMER_NUM_INSTANCES
|
||||
#include <xscutimer.h>
|
||||
#endif
|
||||
#ifdef XPAR_XTMRCTR_NUM_INSTANCES
|
||||
#include <xtmrctr.h>
|
||||
#endif
|
||||
|
||||
/******************************************************************************/
|
||||
/*************************** Types Declarations *******************************/
|
||||
/******************************************************************************/
|
||||
|
||||
/**
|
||||
* @enum xil_timer_type
|
||||
* @brief Xilinx platform architecture sections
|
||||
*/
|
||||
enum xil_timer_type {
|
||||
/** Programmable Logic */
|
||||
TIMER_PL,
|
||||
/** Processing System */
|
||||
TIMER_PS
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct xil_timer_desc
|
||||
* @brief Xilinx specific timer descriptor
|
||||
*/
|
||||
struct xil_timer_desc {
|
||||
/** Pointer to the BSP driver handler */
|
||||
void *instance;
|
||||
/** Pointer to the BSP driver configuration handler */
|
||||
void *config;
|
||||
/** Timer used from the PL 3-timer core */
|
||||
uint8_t active_tmr;
|
||||
/** Platform selection parameter */
|
||||
enum xil_timer_type type;
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct xil_timer_init_param
|
||||
* @brief Xilinx specific timer initialization structure
|
||||
*/
|
||||
struct xil_timer_init_param {
|
||||
/** Timer used from the PL 3-timer core */
|
||||
uint8_t active_tmr;
|
||||
/** Platform selection parameter */
|
||||
enum xil_timer_type type;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Xilinx platform specific timer platform ops structure
|
||||
*/
|
||||
extern const struct timer_platform_ops xil_timer_ops;
|
||||
|
||||
#endif /* XILINX_TIMER_H_ */
|
||||
Reference in New Issue
Block a user