radioberry @pi-5

pull/58/head
pa3gsb 2024-03-25 19:18:49 +01:00
rodzic 9a57ad6083
commit 80f256ab91
8 zmienionych plików z 1094 dodań i 0 usunięć

Wyświetl plik

@ -0,0 +1,25 @@
KERNEL_HEADERS=/lib/modules/$(shell uname -r)/build
obj-m := radioberry.o
all: radioberry dt
echo Build Device Tree Overlay and kernel module.
radioberry:
@$(MAKE) -C $(KERNEL_HEADERS) M=$(PWD) modules
dt:
dtc -@ -I dts -O dtb -o radioberry.dtbo radioberry.dts
clean:
@$(MAKE) -C $(KERNEL_HEADERS) M=$(PWD) clean
install: radioberry.ko
cp radioberry_ioctl.h /usr/local/include
sudo insmod radioberry.ko
sudo chmod 666 /dev/radioberry
uninstall:
sudo rmmod radioberry.ko

Wyświetl plik

@ -0,0 +1,114 @@
## Radioberry Device Driver
This device driver is a special for the RPI-5.
Build step:
First get the linux headers:
sudo apt-get install raspberrypi-kernel-headers
Second you need to start the build process:
use in a command window, in the folder driver (which contains the Makefile) : make
This will results in a radioberry.ko file and radioberry.dtbo file.
Hereby a step by step setup:
Step -1-
CL025 FPGA Radioberry users:
Copy the gateware radioberry.rbf into the folder /lib/firmware
CL016 FPGA Radioberry users:
Rename your radioberry-10CL016.rbf gateware to radioberry.rbf
Copy the gateware radioberry.rbf into the folder /lib/firmware
Loading the device driver will also load the gateware (content of the rbf file) into the FPGA
Step -2-
Make a module folder in the driver area of your running kernel, and install the driver called radioberry.ko in this folder.
cd /lib/modules/$(uname -r)/kernel/drivers
sudo mkdir sdr
copy the radioberry.ko to /lib/modules/$(uname -r)/kernel/drivers/sdr using the command:
sudo cp radioberry.ko /lib/modules/$(uname -r)/kernel/drivers/sdr
Step -3-
run the command: sudo depmod
Check: use the command: sudo modinfo radioberry
Gives you detailed info about the radioberry device driver.
Step -4-
load the device driver:
run the command sudo dtoverlay radioberry.dtbo
run the command: sudo modprobe radioberry
In the folder /dev the radioberry must be present using the ls command.
Also possible to check by the command: lsmod |grep radioberry
Step -5-
Optional step.
cp this radioberry.dtbo into /boot/overlays
add the following line in config.txt:
(location /boot/firmware/config.txt)
dtoverlay=radioberry
This loads the kernel module during boot.
Step -6-
Optional step.
sudo chmod 666 /dev/radioberry
Makes it possible to run the radioberry firmware version for the device driver, running as the logged in user:
Step -7-
Run using the command ./radioberry firmware or sudo ./radioberry
Step -8-
Start a SDR program!
Have fun listening to your Radioberry using the radioberry device driver.
73 Johan
PA3GSB

Wyświetl plik

@ -0,0 +1,414 @@
/*
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <http://unlicense.org/>
sudo cp radioberry.ko /lib/modules/$(uname -r)/kernel/drivers/sdr
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/proc_fs.h>
#include <linux/fcntl.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/uaccess.h>
#include <linux/kthread.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/firmware.h>
#include <linux/circ_buf.h>
#include <linux/wait.h>
#include <linux/mutex.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/interrupt.h>
#include <linux/spi/spi.h>
static struct mutex spi_mutex;
#include "radioberry_rpi.h"
#include "radioberry_ioctl.h"
#include "radioberry_gateware.h"
#include "radioberry_firmware.h"
#define VERSION "5.01"
#define VERSION_INT 501
static DEFINE_MUTEX(radioberry_mutex);
#define DEVICE_NAME "radioberry"
#define DRIVER_NAME "radioberry"
#define CLASS_NAME "radioberry"
static int majorNumber;
static struct class* radioberryCharClass = NULL;
static struct device* radioberryCharDevice = NULL;
#define SAMPLE_BYTES 512
static int _nrx = 1;
static int spi_ctrl_probe(struct spi_device *spi)
{
printk(KERN_INFO "inside %s function \n", __FUNCTION__);
spi_ctrl_dev = spi;
int ret = spi_setup(spi);
if (ret) {
pr_err("Failed to set up SPI communication\n");
return ret;
}
return 0;
}
static void spi_ctrl_remove(struct spi_device *spi)
{
printk(KERN_INFO "inside %s function \n", __FUNCTION__);
}
// Declare the SPI driver structure
static struct spi_driver radioberry_spi_ctrl_driver = {
.driver = {
.name = "radioberry_ctrl_spi",
.owner = THIS_MODULE,
},
.probe = spi_ctrl_probe,
.remove = spi_ctrl_remove,
};
static int spi_tx_probe(struct spi_device *spi)
{
printk(KERN_INFO "inside %s function \n", __FUNCTION__);
spi_tx_dev = spi;
int ret = spi_setup(spi);
if (ret) {
pr_err("Failed to set up SPI communication\n");
return ret;
}
return 0;
}
static void spi_tx_remove(struct spi_device *spi)
{
printk(KERN_INFO "inside %s function \n", __FUNCTION__);
}
// Declare the SPI driver structure
static struct spi_driver radioberry_spi_tx_driver = {
.driver = {
.name = "radioberry_tx_spi",
.owner = THIS_MODULE,
},
.probe = spi_tx_probe,
.remove = spi_tx_remove,
};
static void firmware_load(char *firmware, int size) {
printk(KERN_INFO "inside %s function \n", __FUNCTION__);
u8 *buf = kmalloc(size + 1, GFP_KERNEL);
memcpy(buf, firmware, size);
buf[size] = '\0';
printk(KERN_INFO "Radioberry gateware file size: %d\n", size);
initialize_gateware();
prepare_gateware_loading();
int b = 0;
for (b = 0; b < size; b++) {
upload_gateware_byte(buf[b]);
}
activate_gateware();
kfree(buf);
}
static void loading_radioberry_gateware(struct device *dev) {
printk(KERN_INFO "inside %s function \n", __FUNCTION__);
const struct firmware *fw_entry;
if (request_firmware(&fw_entry, "radioberry.rbf", dev) != 0 ) {
printk(KERN_ERR "gateware radioberry.rbf: Firmware not available\n");
return;
}
firmware_load(fw_entry->data, fw_entry->size);
release_firmware(fw_entry);
}
ssize_t radioberry_read(struct file *flip, char *buf, size_t count, loff_t *pos) {
unsigned char rx_stream[SAMPLE_BYTES]={};
while (read_pin(25) == 0) {udelay(1);};
count = rxStream(_nrx, rx_stream);
if (copy_to_user((char *)buf, &rx_stream, count)) return -EFAULT;
return count;
}
static ssize_t radioberry_write(struct file *flip, const char *buf, size_t count, loff_t *pos) {
unsigned char tx_stream[4];
if (count > 0) {
if (copy_from_user(&tx_stream, buf, sizeof(tx_stream))) {
return -EFAULT;
}
return write_iq_sample(tx_stream);
}
return 0;
}
static int radioberry_open(struct inode *inode, struct file *filep) {
printk(KERN_INFO "inside %s function \n", __FUNCTION__);
if(!mutex_trylock(&radioberry_mutex)){
printk(KERN_ALERT "Radioberry Char: Device in use by another process");
return -EBUSY;
}
int *minor = (int *)kmalloc(sizeof(int), GFP_KERNEL);
int major = MAJOR(inode->i_rdev);
*minor = MINOR(inode->i_rdev);
filep->private_data = (void *)minor;
return 0;
}
static int radioberry_release(struct inode *inode, struct file *filep) {
printk(KERN_INFO "inside %s function \n", __FUNCTION__);
kfree(filep->private_data);
mutex_unlock(&radioberry_mutex);
return 0;
}
static long radioberry_ioctl(struct file *fp, unsigned int cmd, unsigned long arg){
//printk(KERN_INFO "inside %s function \n", __FUNCTION__);
unsigned char data[6];
int lnrx = _nrx;
int rc;
struct rb_info_arg_t *rb_info= kmalloc(sizeof(struct rb_info_arg_t), GFP_DMA);
struct rb_info_arg_t rb_info_ret;
switch(cmd){
case RADIOBERRY_IOC_COMMAND:
rc = copy_from_user(rb_info, (void *)arg, sizeof(struct rb_info_arg_t));
data[0] = ( rb_info->rb_command & 0xFF); //MSB
data[1] = ( rb_info->command & 0xFF);
data[2] = ((rb_info->command_data >> 24) & 0xFF);
data[3] = ((rb_info->command_data >> 16) & 0xFF);
data[4] = ((rb_info->command_data >> 8) & 0xFF);
data[5] = ( rb_info->command_data & 0xFF);
//printk(KERN_INFO "Command kernel %2X - %2X - %2X - %2X - %2X - %2X \n", data[0], data[1], data[2], data[3], data[4], data[5]);
if ((data[1] & 0xFE) == 0x00) lnrx = ((data[5] & 0x38) >> 3) + 1;
mutex_lock(&spi_mutex);
spi_ctrl_Xfer(0, data, data, 6); //spi channel 0 // tell the gateware the command.
mutex_unlock(&spi_mutex);
_nrx = lnrx;
//printk(KERN_INFO "SDR info %2X - %2X - %2X - %2X - %2X - %2X \n", data[0], data[1], data[2], data[3], data[4], data[5]);
// give feedback to firmware.
rb_info_ret.rb_command = data[0]; // return the radioberry status information.
rb_info_ret.major = data[4];
rb_info_ret.minor = data[5];
rb_info_ret.fpga = data[3] & 0x03;
rb_info_ret.version = VERSION_INT;
if (copy_to_user((struct rb_info_arg_t *)arg, &rb_info_ret, sizeof(struct rb_info_arg_t))) return -EACCES;
break;
default:
return -ENOTTY;
}
return 0;
}
static struct file_operations radioberry_fops = {
.owner = THIS_MODULE,
.open = radioberry_open,
.release = radioberry_release,
.write = radioberry_write,
.read = radioberry_read,
.unlocked_ioctl = radioberry_ioctl
};
static int radioberry_probe(struct platform_device *pdev)
{
printk(KERN_INFO "inside %s function \n", __FUNCTION__);
struct device *dev = &pdev->dev;
return 0;
}
static int radioberry_remove(struct platform_device *pdev)
{
printk(KERN_INFO "inside %s function \n", __FUNCTION__);
return 0;
}
static const struct of_device_id of_radioberry_match[] = {
{.compatible = "sdr,radioberry" },
{/*end of list */},
};
MODULE_DEVICE_TABLE(of, of_radioberry_match);
static struct platform_driver radioberry_driver = {
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(of_radioberry_match),
},
.probe = radioberry_probe,
.remove = radioberry_remove,
};
static int __init radioberry_init(void) {
int retval;
size_t size;
printk(KERN_INFO "inside %s function \n", __FUNCTION__);
printk(KERN_INFO "%s loading...\n", DRIVER_NAME);
// Register the SPI driver
int ret = spi_register_driver(&radioberry_spi_ctrl_driver);
if (ret != 0) {
pr_err("Failed to register SPI driver\n");
return ret;
}
printk(KERN_INFO "spi register driver executed with result %d\n", ret);
// Register the SPI driver
ret = spi_register_driver(&radioberry_spi_tx_driver);
if (ret != 0) {
pr_err("Failed to register SPI driver\n");
return ret;
}
printk(KERN_INFO "spi register driver executed with result %d\n", ret);
int result = platform_driver_register(&radioberry_driver);
printk(KERN_INFO "platform driver registered %d \n", result);
// Dynamically allocate a major number for the device
majorNumber = register_chrdev(0, DEVICE_NAME, &radioberry_fops);
if (majorNumber<0){
printk(KERN_ALERT "Radioberry driver failed to register a major number\n");
return majorNumber;
}
printk(KERN_INFO "Radioberry: registered correctly with major number %d\n", majorNumber);
// Register the device class
radioberryCharClass = class_create(CLASS_NAME);
if (IS_ERR(radioberryCharClass)){
unregister_chrdev(majorNumber, DEVICE_NAME);
printk(KERN_ALERT "Failed to register device class\n");
return PTR_ERR(radioberryCharClass);
}
printk(KERN_INFO "Radioberry: device class registered correctly\n");
// Register the device driver
radioberryCharDevice = device_create(radioberryCharClass, NULL, MKDEV(majorNumber, 0), NULL, DEVICE_NAME);
if (IS_ERR(radioberryCharDevice)){
class_destroy(radioberryCharClass);
unregister_chrdev(majorNumber, DEVICE_NAME);
printk(KERN_ALERT "Failed to create the device\n");
return PTR_ERR(radioberryCharDevice);
}
printk(KERN_INFO "Radioberry char: device class created correctly\n");
mutex_init(&radioberry_mutex);
mutex_init(&spi_mutex);
initialize_rpi();
loading_radioberry_gateware(radioberryCharDevice);
initialize_firmware();
return result;
}
static void __exit radioberry_exit(void) {
int i;
printk(KERN_INFO "inside %s function \n", __FUNCTION__);
platform_driver_unregister(&radioberry_driver);
device_destroy(radioberryCharClass, MKDEV(majorNumber, 0));
class_unregister(radioberryCharClass);
class_destroy(radioberryCharClass);
unregister_chrdev(majorNumber, DEVICE_NAME);
mutex_destroy(&radioberry_mutex);
mutex_destroy(&spi_mutex);
// Unregister the SPI driver
spi_unregister_driver(&radioberry_spi_ctrl_driver);
spi_unregister_driver(&radioberry_spi_tx_driver);
deinitialize_rpi();
printk(KERN_INFO "Radioberry: Module removed!\n");
}
module_init(radioberry_init);
module_exit(radioberry_exit);
/**
*
* Radioberry Driver Info
*
*/
MODULE_AUTHOR("Johan Maas - pa3gsb@gmail.com");
MODULE_DESCRIPTION("Radioberry SDR device driver. (rpi-5)");
MODULE_LICENSE("GPL");
MODULE_VERSION(VERSION);

Wyświetl plik

@ -0,0 +1,76 @@
/*
* Device tree overlay for radioberry
*
* Compile:
* dtc -@ -I dts -O dtb -o radioberry.dtbo radioberry.dts
*
* for testing: sudo dtoverlay radioberry.dtbo
*
* add following line in config.txt: dtoverlay=radioberry followed by reboot
*
*
* dtc -I fs /proc/device-tree > devtree.txt (decompile the dt and find the definition for radioberry)
*
* using : dtc -v Version: DTC 1.4.7
*
*/
/dts-v1/;
/plugin/;
/{
compatible = "brcm,bcm2712";
fragment@0 {
target = <&spidev0>;
__overlay__ {
status = "disabled";
};
};
fragment@1 {
target = <&spidev1>;
__overlay__ {
status = "disabled";
};
};
fragment@2 {
target = <&spi0>;
__overlay__ {
status = "okay";
#address-cells = <1>;
#size-cells = <0>;
spi_device_1: radioberry_spi@0 {
compatible = "radioberry_ctrl_spi";
spi-max-frequency = <48000000>;
reg = <0x0>;
spi-bits-per-word = <8>;
spi-mode = <3>;
status = "okay";
};
spi_device_2: radioberry_spi@1 {
compatible = "radioberry_tx_spi";
reg = <0x1>;
spi-max-frequency = <125000000>;
spi-bits-per-word = <8>;
spi-mode = <3>;
status = "okay";
};
};
};
fragment@3 {
target-path = "/";
__overlay__ {
radioberry {
compatible = "sdr,radioberry";
};
};
};
};

Wyświetl plik

@ -0,0 +1,204 @@
#ifndef __RADIOBERRY_FIRMWARE_H__
#define __RADIOBERRY_FIRMWARE_H__
#define GPIO_FUNC_SPI 0
#define RPI_RX_CLK 6
#define RPI_SPI_CE0 8
#define RPI_SPI_CE1 7
#define RPI_SPI_SCLK 11
#define RPI_SPI_MISO 9
#define RPI_SPI_MOSI 10
static struct spi_device *spi_ctrl_dev;
static struct spi_device *spi_tx_dev;
static int initialize_firmware(void);
int rxStream(int nrx, unsigned char stream[]);
void read_iq_sample(int lnrx, int iqs, unsigned char iqdata[]);
int spiXfer(int spi_channel, char *txBuf, char *rxBuf, unsigned cnt);
int write_iq_sample(unsigned char tx_iqdata[]);
static int initialize_firmware() {
printk(KERN_INFO "initialize_firmware: make GPIO ready for rx and tx streaming...\n");
// disable the SPI
*(volatile uint32_t *)(SPIBase + DW_SPI_SSIENR) = 0x0;
// SPI Mode Pins
setPinMode(RPI_SPI_CE0, GPIO_FUNC_SPI);
setPinMode(RPI_SPI_CE1, GPIO_FUNC_SPI);
setPinMode(RPI_SPI_SCLK, GPIO_FUNC_SPI);
setPinMode(RPI_SPI_MISO, GPIO_FUNC_SPI);
setPinMode(RPI_SPI_MOSI, GPIO_FUNC_SPI);
// SPI control settings
// set the speed - this is the divisor from 200MHz in the RPi5
*(volatile uint32_t *)(SPIBase + DW_SPI_BAUDR) = 20;
// set mode - CPOL = 1, CPHA = 1 (Mode 3)
*(volatile uint32_t *)(SPIBase + DW_SPI_CTRLR0) |= DW_PSSI_CTRLR0_SCPHA;
*(volatile uint32_t *)(SPIBase + DW_SPI_CTRLR0) |= DW_PSSI_CTRLR0_SCPOL;
// enable the SPI
*(volatile uint32_t *)(SPIBase + DW_SPI_SSIENR) = 0x1;
//RX IO Init part
initialize_gpio_for_output(RPI_RX_CLK);
clr_pin(RPI_RX_CLK); // init pi-rx_clk
initialize_gpio_for_input(23); // rx iq data
initialize_gpio_for_input(20); // rx iq data
initialize_gpio_for_input(19); // rx iq data
initialize_gpio_for_input(18); // rx iq data
initialize_gpio_for_input(16); // rx iq data
initialize_gpio_for_input(13); // rx iq data
initialize_gpio_for_input(12); // rx iq data
initialize_gpio_for_input( 5); // rx iq data
initialize_gpio_for_input(25); // available samples.
printk(KERN_INFO "GPIO ready for rx and tx streaming...\n");
return 0;
}
int spi_ctrl_Xfer(int spi_channel, char *txBuf, char *rxBuf, unsigned cnt){
//printk(KERN_INFO "inside %s function \n", __FUNCTION__);
struct spi_transfer t = {
.tx_buf = txBuf,
.rx_buf = rxBuf,
.len = cnt,
};
struct spi_message m;
spi_message_init(&m);
spi_message_add_tail(&t, &m);
//spi_ctrl_dev->chip_select = spi_channel;
// Send and receive the message to/from the Radioberry SPI device
int ret = spi_sync(spi_ctrl_dev, &m);
if (ret) {
pr_err("SPI transfer failed\n");
return ret;
}
return 0;
}
/*
Using the spi driver was not working fast enough.
int spi_tx_Xfer(int spi_channel, char *txBuf, char *rxBuf, unsigned cnt){
//printk(KERN_INFO "inside %s function \n", __FUNCTION__);
struct spi_transfer t = {
.tx_buf = txBuf,
.rx_buf = rxBuf,
.len = cnt,
};
struct spi_message m;
spi_message_init(&m);
spi_message_add_tail(&t, &m);
// Send and receive the message to/from the Radioberry SPI device
int ret = spi_sync(spi_tx_dev, &m);
if (ret) {
pr_err("SPI transfer failed\n");
return ret;
}
return 0;
}
*/
int spi_tx_Xfer(int spi_channel, char *txBuf, char *rxBuf, unsigned cnt)
{
//printk(KERN_INFO "inside %s function \n", __FUNCTION__);
// set the frame size to 32 bits
*(volatile uint32_t *)(SPIBase + DW_SPI_CTRLR0) = ((*(volatile uint32_t *)(SPIBase + DW_SPI_CTRLR0)) | DW_PSSI_CTRLR0_DFS32_MASK | DW_PSSI_CTRLR0_DFS_MASK);
// write the tx fifo
unsigned txCnt = 0;
while((*(volatile uint32_t *)(SPIBase + DW_SPI_SR) & DW_SPI_SR_TF_NOT_FULL) && (txCnt < cnt))
{
*(volatile uint8_t *)(SPIBase + DW_SPI_DR) = (uint8_t)txBuf[txCnt];
txCnt++;
}
//spi control
*(volatile uint32_t *)(SPIBase + DW_SPI_SER) = 1 << spi_channel; // CE1 active
// transfer the tx fifo and fill the rx fifo
int rxCnt = 0;
while(rxCnt < cnt)
{
// check if there is data to read (check status register for Read Fifo Not Empty)
if(*(volatile uint32_t *)(SPIBase + DW_SPI_SR) & DW_SPI_SR_RF_NOT_EMPT)
{
rxBuf[rxCnt] = *(volatile uint8_t *)(SPIBase + DW_SPI_DR);
rxCnt++;
}
}
//spi control
*(volatile uint32_t *)(SPIBase + DW_SPI_SER) = 0x00; //CE1 inactive
return 0;
}
int rxStream(int nrx, unsigned char stream[]){
unsigned char iqdata[6];
int iqs = 1;
int nr_samples = (nrx == 1)? 63 : (nrx == 2)? 72: (nrx ==3)? 75: (nrx ==4)? 76: (nrx ==5)? 75: (nrx ==6)? 78: (nrx ==7)? 77: 80;
int s = 0;
for (s = 0; s < nr_samples; s++) {
read_iq_sample(nrx, iqs, iqdata);
memcpy(stream + (s * 6), iqdata, 6);
iqs++;
}
return nr_samples * 6;
}
void read_iq_sample(int lnrx, int iqs, unsigned char iqdata[]){
uint32_t value = 0;
for (int i = 0; i < 6 ; i++) {
if (i % 2 == 0) set_pin(RPI_RX_CLK); else clr_pin(RPI_RX_CLK);
ndelay(100);
value = read_pin_all();
iqdata[i] = (((value >> 23) & 1) << 7);
iqdata[i] |= (((value >> 20) & 1) << 6);
iqdata[i] |= (((value >> 19) & 1) << 5);
iqdata[i] |= (((value >> 18) & 1) << 4);
iqdata[i] |= (((value >> 16) & 1) << 3);
iqdata[i] |= (((value >> 13) & 1) << 2);
iqdata[i] |= (((value >> 12) & 1) << 1);
iqdata[i] |= (((value >> 5) & 1));
}
}
int write_iq_sample(unsigned char tx_iqdata[]) {
unsigned char data[4];
mutex_lock(&spi_mutex);
spi_tx_Xfer(1, tx_iqdata, data, 4); //spi channel 1; write IQ sample (4bytes)
mutex_unlock(&spi_mutex);
return 4;
}
#endif

Wyświetl plik

@ -0,0 +1,103 @@
/**
*
* Loading the gateware into the FPGA.
*
*/
#ifndef __RADIOBERRY_GATEWARE_H__
#define __RADIOBERRY_GATEWARE_H__
#include <linux/delay.h>
#define iPinCONF_DONE 22
#define iPinNSTATUS 26
#define oPinNCONFIG 27
#define oPinDATA 13
#define oPinDCLK 24
static void initialize_gateware(void);
static int prepare_gateware_loading(void) ;
static void upload_gateware_byte( int one_byte );
static int activate_gateware(void);
static void upload_gateware_byte( int one_byte ) {
int bit = 0;
int i = 0;
/* write from LSb to MSb */
for ( i = 0; i < 8; i++ )
{
bit = one_byte >> i;
bit = bit & 0x1;
if (bit) set_pin(oPinDATA); else clr_pin(oPinDATA);
udelay(1);
set_pin(oPinDCLK);
clr_pin(oPinDCLK);
}
}
static int prepare_gateware_loading() {
printk(KERN_INFO "Info: prepare FPGA for loading image\n");
clr_pin(oPinNCONFIG);
clr_pin(oPinDATA);
clr_pin(oPinDCLK);
msleep(1000);
set_pin(oPinNCONFIG);
int count = 0;
while (read_pin(iPinNSTATUS) == 0) {
count++;
msleep(1000);
if (count >= 2) {
printk(KERN_INFO "Error: prepareLoading failed\n");
return -1;
}
}
return 0;
}
static void initialize_gateware() {
initialize_gpio_for_input(iPinCONF_DONE);
initialize_gpio_for_input(iPinNSTATUS);
initialize_gpio_for_output(oPinNCONFIG);
initialize_gpio_for_output(oPinDATA);
initialize_gpio_for_output(oPinDCLK);
printk(KERN_INFO "GPIO ready for uploading gateware...\n");
}
static int activate_gateware() {
/* Check if loading succeeded*/
if (read_pin(iPinNSTATUS) == 0) {
printk(KERN_INFO "Error: programming failed; nstatus is low\n");
return 0;
} else if (read_pin(iPinCONF_DONE) == 0) {
printk(KERN_INFO "Error: programming failed; conf done is low\n");
return 0;
}
/* Initialize device */
set_pin(oPinDCLK);
clr_pin(oPinDCLK);
set_pin(oPinDCLK);
clr_pin(oPinDCLK);
printk(KERN_INFO "Info: gateware upload and activation succeeded\n");
return 0;
}
#endif

Wyświetl plik

@ -0,0 +1,25 @@
#ifndef __RADIOBERRY_IOCTL_H__
#define __RADIOBERRY_IOCTL_H__
#include <linux/types.h>
#include <linux/ioctl.h>
#define RADIOBERRY_MAGIC ('x')
#define RADIOBERRY_IOC_COMMAND _IOW(RADIOBERRY_MAGIC, 1, __u8)
struct rb_info_arg_t
{
int major, minor;
int fpga;
int version;
int rb_command;
int command;
int command_data;
} ;
#endif

Wyświetl plik

@ -0,0 +1,133 @@
/**
*
* GPIO RPI-5 functions.
*
*/
#ifndef __RADIOBERRY_RPI_H__
#define __RADIOBERRY_RPI_H__
#define GPIO ((GPIOregs*)GPIOBase)
#define PERI_BASE 0x1F00000000
#define MEM_SIZE (64 * 1024 * 1024)
#define RP1_SPI0_BASE 0x050000
#define DW_SPI_CTRLR0 0x00 // control register 0 (frame format, clock polarity, phase, etc.)
#define DW_SPI_SSIENR 0x04 // enable register (enable/disable the SPI controller) (0x08)
#define DW_SPI_SER 0x04 // chip select, bit = chip select line (0x10)
#define DW_SPI_BAUDR 0x05 // baud rate register (0x14)
#define DW_SPI_SR 0x0a // status register (0x28)
#define DW_SPI_DR 0x18 // data register (0x60)
// 10987654321098765432109876543210
#define DW_PSSI_CTRLR0_DFS_MASK 0b00000000000000000000000000001111 //GENMASK(3, 0)
#define DW_PSSI_CTRLR0_DFS32_MASK 0b00000000000111110000000000000000 //GENMASK(20, 16)
//SPI
#define DW_PSSI_CTRLR0_MODE_MASK 0b00000000000000000000000011000000 //GENMASK(7, 6)
#define DW_PSSI_CTRLR0_SCPHA 0b00000000000000000000000001000000 // BIT(6)
#define DW_PSSI_CTRLR0_SCPOL 0b00000000000000000000000010000000 //BIT(7)
/* Bit fields in SR, 7 bits */
#define DW_SPI_SR_TF_NOT_FULL 0b00000000000000000000000000000010 // BIT(1)
#define DW_SPI_SR_RF_NOT_EMPT 0b00000000000000000000000000001000 // BIT(3)
typedef struct{
uint32_t status;
uint32_t ctrl;
} GPIOregs;
typedef struct
{
uint32_t out;
uint32_t oe;
uint32_t in;
uint32_t inSync;
} rioregs;
volatile uint32_t *PERIBase = NULL;
volatile uint32_t *GPIOBase = NULL;
volatile uint32_t *RIOBase = NULL;
volatile uint32_t *PADBase = NULL;
volatile uint32_t *SPIBase = NULL;
uint32_t *Pad = NULL;
#define rio ((rioregs *)RIOBase)
#define rioSET ((rioregs *)(RIOBase + 0x2000 / 4))
#define rioCLR ((rioregs *)(RIOBase + 0x3000 / 4))
#define GPIO_FUNC_RIO 5
#define PAD_FUNC_IN 0xC8
#define PAD_FUNC_OUT 0x10
static int initialize_rpi(void) {
int ret = 0;
printk(KERN_INFO "make GPIO ready for use\n");
if((PERIBase = ioremap(PERI_BASE, MEM_SIZE)) == NULL){
printk(KERN_INFO "Failed mapping registers...\n");
ret = -1;
}
GPIOBase = PERIBase + 0xD0000 / 4;
RIOBase = PERIBase + 0xE0000 / 4;
PADBase = PERIBase + 0xF0000 / 4;
Pad = PADBase + 1;
SPIBase = PERIBase + RP1_SPI0_BASE / 4;
printk(KERN_INFO "GPIO ready for use\n");
return ret;
}
static void deinitialize_rpi(void) {
iounmap(PERIBase);
printk(KERN_INFO "GPIO resources free. \n");
}
static void initialize_gpio_for_output(uint32_t pin) {
GPIO[pin].ctrl=GPIO_FUNC_RIO;
Pad[pin] = PAD_FUNC_OUT;
rioSET->oe = 0x01<<pin; // output driver
}
static void initialize_gpio_for_input(uint32_t pin) {
GPIO[pin].ctrl=GPIO_FUNC_RIO;
Pad[pin] = PAD_FUNC_IN;
rioCLR->oe = 0x01<<pin; // high impedance
}
static void set_pin(uint32_t pin) {
rioSET->oe = 0x01<<pin; // output driver
rioSET->out = 0x01<<pin;
}
static void clr_pin(uint32_t pin) {
rioSET->oe = 0x01<<pin; // output driver
rioCLR->out = 0x01<<pin;
}
static uint32_t read_pin(uint32_t pin) {
return (rio->in>>pin & 0x01);
}
static uint32_t read_pin_all(void) {
return rio->in;
}
static void setPinMode(uint32_t pin, uint32_t mode)
{
GPIO[pin].ctrl = mode;
}
#endif