mlukaszek
Posts: 2
Joined: Thu Sep 25, 2014 9:45 am

RPi B+ as I2C/BSC slave?

Thu Sep 25, 2014 10:04 am

Hi,

I am wondering if a Raspberry Pi B+ can be used as a I2C slave, so it can be connected to an existing I2C bus which already has one master (that cannot do multi-master).

I did read an earlier thread that said it's impossible due to PIN 19 (BSCSL SCL) of BCM2835 being left unconnected.
However, if I read http://elinux.org/RPi_BCM2835_GPIOs right, this has changed with B+ model release, and it looks available now on pin 35.

Has anyone tried already and was successful?
What's the quickest/easiest way one can write software that can act as a slave and respond to master's queries?
Is there any library like wiringpi for example, that would provide means to make such task easier?

Many thanks,
Michal

User avatar
DougieLawson
Posts: 36130
Joined: Sun Jun 16, 2013 11:19 pm
Location: Basingstoke, UK
Contact: Website Twitter

Re: RPi B+ as I2C/BSC slave?

Thu Sep 25, 2014 10:44 am

It can't be done on the kernel supported I2C bus. So you'd have to bit bang it yourself on other pins. Without using a kernel driver you may have problems getting the timing right.

It may be easier to use an Arduino as the I2C slave and have it act as a broker for the Pi.
Note: Having anything humorous in your signature is completely banned on this forum. Wear a tin-foil hat and you'll get a ban.

Any DMs sent on Twitter will be answered next month.

This is a doctor free zone.

User avatar
joan
Posts: 14264
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: RPi B+ as I2C/BSC slave?

Thu Sep 25, 2014 11:22 am

The B+ exposes the gpios needed (18-21) to use the Broadcom peripheral slave SPI/I2C device. I had a quick look and don't think there is any point in using the peripheral from userland. I suppose someone could write a kernel driver to be used on the B+ and compute module.

mlukaszek
Posts: 2
Joined: Thu Sep 25, 2014 9:45 am

Re: RPi B+ as I2C/BSC slave?

Thu Sep 25, 2014 11:28 am

I feared this would be the case. I'll probably fall back to another interface then, or go with your advice and introduce a broker chip.
Time is short for my project, I doubt I would have enough time to try and write a kernel module. :(

Thanks a lot,
Michal

Hendric
Posts: 5
Joined: Fri Oct 10, 2014 4:36 pm

Re: RPi B+ as I2C/BSC slave?

Wed Jan 28, 2015 5:21 pm

Hi,

I had some time and I wrote a simple kernel module to test the functionality but I am stick with it.
The problem is that I don't really know how to initialize the SPI/BSC Slave. I try to realize a SPI Slave but for the I2C Slave the differences aren't certainly so big.

I mostly try to activate it via the CR Register. Bit EN and SPI in the datasheet page 165.

I only had acces to the BCM2835 ARM Peripherals pdf.

Does anybody know where to download the full documentation?
Has anybody made the SPI/BSC Slave working?

for the following code it is possible to put some data in the FIFO and to read the content by

echo 8 > /sys/devices/platform/drive-controller.0/sendValue

the answer appears in the log message:

dmesg | tail


thank a lot for help

Code: Select all

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/err.h>

#include<asm/system.h>

#include <linux/clk.h>
#include <linux/io.h>
#include <linux/spi/spi.h>
#include <linux/delay.h>
#include <linux/log2.h>

 
#define DRIVER_AUTHOR "Hendrik <[email protected]>"
#define DRIVER_DESC   "Drive controller"
 
// text below will be seen in 'cat /proc/interrupt' command
#define IRQ_DESC                "Spi-Slave-Irq"
#define DEVICE_DESC             "drive-controller-_device"
#define DRV_NAME                "drive-controller" 
#define BUFFER_SIZE             40
#define IRQ_NUMBER		43

#define BCM2708_PERI_BASE        0x20000000
#define SPI_SLAVE_BASE           (BCM2708_PERI_BASE + 0x214000)


/* SPI SLAVE register offsets */
#define SPI_DR			0x00
#define SPI_RSR 		0x04
#define SPI_CR  		0x0c
#define SPI_FR	        	0x10
#define SPI_IFLS		0x14
#define SPI_IMSC		0x18
#define SPI_RIS			0x1c
#define SPI_MIS			0x20
#define SPI_ICR			0c24

/* Bitfields in DR */
#define SPI_DR_RXFLEVEL_MASK	0xF8000000
#define SPI_DR_TXFLEVEL_MASK	0x07c00000
#define SPI_DR_RXBUSY		0x00200000
#define SPI_DR_TXFE		0x00100000
#define SPI_DR_RXFF		0x00080000
#define SPI_DR_TXFF		0x00040000
#define SPI_DR_RXFE		0x00020000
#define SPI_DR_TXBUSY		0x00010000
#define SPI_DR_DATA_MASK	0x000000FF
 
/* Bitfields in CR */
#define SPI_CR_RXE              0x00000200
#define SPI_CR_TXE              0x00000100
#define SPI_CR_BRK              0x00000080
#define SPI_CR_CPOL             0x00000010
#define SPI_CR_CPHA             0x00000008
#define SPI_CR_I2C              0x00000004
#define SPI_CR_SPI	        0x00000002
#define SPI_CR_EN	        0x00000001

/* Bitfields in IMSC */
#define SPI_IMSC_TXIM           0x00000002
#define SPI_IMSC_RXIM		0x00000001

/* Bitfields in ICR */
#define SPI_ICR_TXIC		0x00000002

struct bcm2708_drive_controller_struct {
       void  __iomem *base;
       int           irq;

       u8            *tx_buf;
       u8            *rx_buf;
       int           len;
}; 
 

/****************************************************************************/
/*                     Initialize GPIO for SPI-control                      */
/****************************************************************************/
static void bcm2708_init_spi_pinmode(void)
{
//#define INP_GPIO(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3))
//#define SET_GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3))

//	int pin;
	void __iomem *gpio;
        u32 reg;

        printk(KERN_NOTICE "Init spi pin mode!\n");
        gpio = ioremap(GPIO_BASE, SZ_16K);

/*	// SPI Slave is on GPIO 18..21 
	for (pin = 18; pin <= 21; pin++) {
		INP_GPIO(pin);		// set mode to GPIO input first 
		SET_GPIO_ALT(pin, 3);	// set mode to ALT 3 
	}*/
  reg = readl(gpio + 0x04);
  reg |= (0b111111 << 24);   //ALT3 for Pins 18 and 19
  writel(reg, gpio + 0x04);
  printk(KERN_NOTICE "FSEL1 Register : 0x%08lx \n", (unsigned long)reg);
  reg = readl(gpio + 0x08);
  reg |= 0b111111;           //ALT3 for Pins 20 ans 21
  writel(reg, gpio + 0x08);
  printk(KERN_NOTICE "FSEL2 Register : 0x%08lx \n", (unsigned long)reg);
	iounmap(gpio);

//#undef INP_GPIO
//#undef SET_GPIO_ALT
}



/****************************************************************************/
/* IRQ handler - fired on interrupt                                         */
/****************************************************************************/
static irqreturn_t controller_irq_handler(int irq, void *dev_id) {
 
   unsigned long flags;
   u32 mis;
   struct bcm2708_drive_controller_struct *drive_controller = dev_id;

   mis  = readl(drive_controller->base + SPI_MIS);
 /*  if( cs & SPI_CS_DONE){
 //     if(!drive_controller->len)
      cs &= ~(SPI_CS_INTR | SPI_CS_INTD | SPI_CS_TA);
      writel(cs, drive_controller->base);
   }*/ 

   local_irq_save(flags);              //disable hard interrupts;save in flag

   printk(KERN_NOTICE "Interrupt [%d] for device was triggered !.\n",
          irq);
 
   local_irq_restore(flags);          //restore interrupts
 
   return IRQ_HANDLED;
}
 
/****************************************************************************/
/*                      Module probe and remove block.                      */
/****************************************************************************/

static int bcm2708_drive_controller_probe(struct platform_device *pdev){
  struct bcm2708_drive_controller_struct *drive_controller;
  struct resource *regs;
  int irq, err;
  u32 reg = 0;

  printk(KERN_NOTICE "Enter drive controller probe method!\n");


  regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  if(!regs){
     dev_err(&pdev->dev, "could not get IO memory\n");
     return -ENXIO;
  }
  
  irq = platform_get_irq(pdev, 0);
  if(irq < 0){
     dev_err(&pdev->dev, "could not get IRQ\n");
     return irq;
  }


  bcm2708_init_spi_pinmode();

  drive_controller = kmalloc(sizeof(struct bcm2708_drive_controller_struct),
                             GFP_KERNEL);
  if(!drive_controller){
     dev_err(&pdev->dev, "could not allocate memory!\n");
     return -ENOMEM;
  }

  memset(drive_controller, 0, sizeof(struct bcm2708_drive_controller_struct));

  drive_controller->tx_buf = kmalloc(BUFFER_SIZE, GFP_KERNEL);

  if(!(drive_controller->tx_buf)){
     dev_err(&pdev->dev, "could not allocate memory!\n");
     return -ENOMEM;
  }
  memset(drive_controller->tx_buf, 0, BUFFER_SIZE);

  drive_controller->rx_buf = kmalloc(BUFFER_SIZE, GFP_KERNEL);

  if(!(drive_controller->rx_buf)){
     dev_err(&pdev->dev, "could not allocate memory!\n");
     return -ENOMEM;
  }
  memset(drive_controller->rx_buf, 0, BUFFER_SIZE);


  err = request_irq(irq, controller_irq_handler, 0, dev_name(&pdev->dev),
                    drive_controller);
  if(err){
     dev_err(&pdev->dev, "could not request IRQ: %d!\n", err);
     goto irq_fail;
  }

  drive_controller->irq = irq;

  drive_controller->base = ioremap(regs->start, resource_size(regs));
  if(!drive_controller->base){
     dev_err(&pdev->dev, "could not remap memory!\n");
//     goto remap_fail;
  }

  platform_set_drvdata(pdev, drive_controller);

 // reg = readl(drive_controller->base + SPI_IMSC);
  reg |= SPI_IMSC_RXIM;
  iowrite32(reg, drive_controller->base + SPI_IMSC);

  reg = 0;
  reg &= ~(SPI_CR_CPHA | SPI_CR_CPOL);
  reg |= (SPI_CR_SPI | SPI_CR_RXE | SPI_CR_TXE);

  iowrite32(reg, drive_controller->base + SPI_CR);
  reg |= (SPI_CR_EN);
  iowrite32(reg, drive_controller->base + SPI_CR);

  dev_info(&pdev->dev, "Drive Controller at 0x%08lx (irq %d)\n",
                       (unsigned long)regs->start, irq);

/* remap_fail:
//    free_irq(irq, 0);
*/
  irq_fail:

  return 0;
}

static int bcm2708_drive_controller_remove(struct platform_device *pdev){

  struct bcm2708_drive_controller_struct *drive_controller;

  printk(KERN_NOTICE "Drive controller remove method evoked!\n");
  drive_controller = platform_get_drvdata(pdev);

  kfree(drive_controller->tx_buf);
  kfree(drive_controller->rx_buf);
 
  free_irq(drive_controller->irq, drive_controller);
  kfree(drive_controller);
  platform_set_drvdata(pdev, NULL); 

  return 0;
}

/***************************************************************************/
/*                   sysfs interface to userspace                          */
/***************************************************************************/

static ssize_t send_value(struct device *dev, struct device_attribute *attr,
                          const char *buffer, size_t count){
 
  u32 reg;
  int value;
  struct bcm2708_drive_controller_struct *drive_controller;

  sscanf(buffer, "%d", &value);
  drive_controller = dev_get_drvdata(dev);

  printk(KERN_NOTICE "send value is %d\n", value);
  reg = readl(drive_controller->base + SPI_DR);
  printk(KERN_NOTICE "DR Register before send: 0x%08lx \n", (unsigned long)reg);
  writeb(value, drive_controller->base + SPI_DR);

  reg = readl(drive_controller->base + SPI_DR);
  printk(KERN_NOTICE "DR Register after send: 0x%08lx \n", (unsigned long)reg);
  
  reg = readl(drive_controller->base + SPI_CR);
  printk(KERN_NOTICE "CR Register is: 0x%08lx \n", (unsigned long)reg);

  return count;
}

DEVICE_ATTR(sendValue, 0644, NULL, send_value);

static struct attribute *drive_controller_attrs[] = {
  &dev_attr_sendValue.attr,
  NULL
};

static struct attribute_group drive_controller_attr_group = {
  .attrs = drive_controller_attrs,
};

/****************************************************************************/
/*                           platform specifics                             */
/*        resource and device definition should stand in bcm2708.c          */
/****************************************************************************/

static struct resource bcm2708_drive_controller_resources[] = {
         {
                   .start = SPI_SLAVE_BASE,
                   .end   = SPI_SLAVE_BASE + SZ_256 -1,
                   .flags = IORESOURCE_MEM,
         }, {
                   .start = IRQ_NUMBER,
                   .end   = IRQ_NUMBER,
                   .flags = IORESOURCE_IRQ,
         }
};


struct platform_device *drive_controller_device;

static struct platform_driver bcm2708_drive_controller_driver = {
        .driver          =  {
                .name    =  DRV_NAME,
                .owner   =  THIS_MODULE,
        },
        .probe           = bcm2708_drive_controller_probe,
        .remove          = bcm2708_drive_controller_remove,
};


/***************************************************************************/
/*                          controller-init                                */
/***************************************************************************/

int controller_init(void) {
 
  int retvalue; 

   drive_controller_device = platform_device_register_simple(DRV_NAME,0,
                                   bcm2708_drive_controller_resources, 2);
   if(IS_ERR(drive_controller_device)){
      printk(KERN_NOTICE "failed to register platform controller driver!\n");
      return 0;
   }

   retvalue = sysfs_create_group(&drive_controller_device->dev.kobj, 
                      &drive_controller_attr_group);
   if(retvalue){
        printk(KERN_NOTICE "Unable to create group for  controller_driver\n");
        platform_device_unregister(drive_controller_device);
        return -ENOMEM;
   }


   retvalue = platform_driver_register(&bcm2708_drive_controller_driver);

   if(retvalue){
        printk(KERN_NOTICE "Unable to register controller_driver\n");
        platform_device_unregister(drive_controller_device);
   }

   return 0;
}
 
void controller_cleanup(void) {
   printk(KERN_NOTICE "spi interrupt handler module exit\n");
   sysfs_remove_group(&drive_controller_device->dev.kobj, 
                      &drive_controller_attr_group);
   platform_device_unregister(drive_controller_device);
   platform_driver_unregister(&bcm2708_drive_controller_driver);

   return;
}
 
 
module_init(controller_init);
module_exit(controller_cleanup);
 
 
/****************************************************************************/
/* Module licensing/description block.                                      */
/****************************************************************************/

MODULE_LICENSE("GPL");
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_ALIAS("platform:" DRV_NAME);

rst
Posts: 409
Joined: Sat Apr 20, 2013 6:42 pm
Location: Germany

Re: RPi B+ as I2C/BSC slave?

Wed Jan 28, 2015 10:04 pm

I got the BSC / SPI slave (I2C compatible mode) running in a bare metal environment:

https://github.com/rsta2/circle/blob/ma ... cslave.cpp

It's a polling driver which is used in a sample to echo I2C packets received from the master back to it. Perhaps it helps to set up the registers right.

Hendric
Posts: 5
Joined: Fri Oct 10, 2014 4:36 pm

Re: RPi B+ as I2C/BSC slave?

Fri Jun 05, 2015 12:01 pm

ok. I finished the above kernel module and got it working for the i2c slave functionality.
The SPI Slave mode is not working yet. I have no ideas of how to make it working so any ideas
are welcome.

This is my first kernel module so it could be buggy. Would be glad if somebody contributes.

The module with some instructions can be downloaded at:

https://github.com/hendric-git/bsc-slave

special thanks to rst your code helped me developing

jdb
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 2094
Joined: Thu Jul 11, 2013 2:37 pm

Re: RPi B+ as I2C/BSC slave?

Fri Jun 12, 2015 10:30 am

Just a note that slave i2c adapter support is available in the upstream kernel - take a look at:

http://lxr.free-electrons.com/source/in ... i2c.h#L254

If someone wants to write the driver for BSC slave then push it upstream...
Rockets are loud.
https://astro-pi.org

ReneA
Posts: 1
Joined: Thu Jul 16, 2015 6:21 pm

Re: RPi B+ as I2C/BSC slave?

Thu Jul 16, 2015 6:30 pm

I just registered to the forum to say thank you to hendric.
Your kernel module works like a charm for my raspberry pi b+.

It took only some time to find the linux header files for my kernel to compile the module.
(Found it >>here<<)

And i was so stupid that i wonder for several hours why i cannot connect to my pi slave ...
The problem was that I still used the I2C pins and not BCM18 for SDA and BCM19 for SCL :?
Maybe you could add this information in the readme-file.

Thx a lot!

coluna
Posts: 1
Joined: Mon Jul 20, 2015 3:22 pm

Re: RPi B+ as I2C/BSC slave?

Mon Jul 20, 2015 3:44 pm

Hi,

I have a Raspberry pi B+ and I need to use it as a slave i2c reader.
I'm trying to use Hendric's kernel module but i'm completly beginner in that.
as my kernel version is not the good one i followed this link https://github.com/Hexxeh/rpi-update for rpi-update
and this one https://github.com/notro/rpi-source/wiki for kernel sources but whatever i do i have this error :

ERROR:
gcc version check: mismatch between gcc (4.8.2) and /proc/version (4.0.8)
Skip this check with --skip-gcc

cat /proc/version give me that
Linux version 4.0.8+ ([email protected]) (gcc version 4.8.3 20140303 (prerelease) (crosstool-NG linaro-1.13.1+bzr2650 - linaro GCC 2014.03) ) #805 PREEMPT Thu Jul 16 18:09:07 BST 2015

and gcc --version give me that
gcc (Raspbian 4.8.2-21~rpi3rpi1) 4.8.2

finally if i try to do make
make -C /lib/modules/4.0.8+/build M=/home/pi/raspPi/bsc-slave-master modules
make[1]: *** /lib/modules/4.0.8+/build: No such file or directory. Stop.
Makefile:4: recipe for target 'all' failed
make: *** [all] Error 2

and if i try to do sudo insmod bsc-slave.ko
Error: could not insert module bsc-slave.ko: Invalid module format

any help will be welcome :)

thx

krishnaiah.vv
Posts: 19
Joined: Wed Jun 24, 2015 7:34 am

Re: RPi B+ as I2C/BSC slave?

Tue Aug 04, 2015 12:01 pm

Hendric wrote:Hi,

I had some time and I wrote a simple kernel module to test the functionality but I am stick with it.
The problem is that I don't really know how to initialize the SPI/BSC Slave. I try to realize a SPI Slave but for the I2C Slave the differences aren't certainly so big.

I mostly try to activate it via the CR Register. Bit EN and SPI in the datasheet page 165.

I only had acces to the BCM2835 ARM Peripherals pdf.

Does anybody know where to download the full documentation?
Has anybody made the SPI/BSC Slave working?

for the following code it is possible to put some data in the FIFO and to read the content by

echo 8 > /sys/devices/platform/drive-controller.0/sendValue

the answer appears in the log message:

dmesg | tail


thank a lot for help

Code: Select all

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/err.h>

#include<asm/system.h>

#include <linux/clk.h>
#include <linux/io.h>
#include <linux/spi/spi.h>
#include <linux/delay.h>
#include <linux/log2.h>

 
#define DRIVER_AUTHOR "Hendrik <[email protected]>"
#define DRIVER_DESC   "Drive controller"
 
// text below will be seen in 'cat /proc/interrupt' command
#define IRQ_DESC                "Spi-Slave-Irq"
#define DEVICE_DESC             "drive-controller-_device"
#define DRV_NAME                "drive-controller" 
#define BUFFER_SIZE             40
#define IRQ_NUMBER		43

#define BCM2708_PERI_BASE        0x20000000
#define SPI_SLAVE_BASE           (BCM2708_PERI_BASE + 0x214000)


/* SPI SLAVE register offsets */
#define SPI_DR			0x00
#define SPI_RSR 		0x04
#define SPI_CR  		0x0c
#define SPI_FR	        	0x10
#define SPI_IFLS		0x14
#define SPI_IMSC		0x18
#define SPI_RIS			0x1c
#define SPI_MIS			0x20
#define SPI_ICR			0c24

/* Bitfields in DR */
#define SPI_DR_RXFLEVEL_MASK	0xF8000000
#define SPI_DR_TXFLEVEL_MASK	0x07c00000
#define SPI_DR_RXBUSY		0x00200000
#define SPI_DR_TXFE		0x00100000
#define SPI_DR_RXFF		0x00080000
#define SPI_DR_TXFF		0x00040000
#define SPI_DR_RXFE		0x00020000
#define SPI_DR_TXBUSY		0x00010000
#define SPI_DR_DATA_MASK	0x000000FF
 
/* Bitfields in CR */
#define SPI_CR_RXE              0x00000200
#define SPI_CR_TXE              0x00000100
#define SPI_CR_BRK              0x00000080
#define SPI_CR_CPOL             0x00000010
#define SPI_CR_CPHA             0x00000008
#define SPI_CR_I2C              0x00000004
#define SPI_CR_SPI	        0x00000002
#define SPI_CR_EN	        0x00000001

/* Bitfields in IMSC */
#define SPI_IMSC_TXIM           0x00000002
#define SPI_IMSC_RXIM		0x00000001

/* Bitfields in ICR */
#define SPI_ICR_TXIC		0x00000002

struct bcm2708_drive_controller_struct {
       void  __iomem *base;
       int           irq;

       u8            *tx_buf;
       u8            *rx_buf;
       int           len;
}; 
 

/****************************************************************************/
/*                     Initialize GPIO for SPI-control                      */
/****************************************************************************/
static void bcm2708_init_spi_pinmode(void)
{
//#define INP_GPIO(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3))
//#define SET_GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3))

//	int pin;
	void __iomem *gpio;
        u32 reg;

        printk(KERN_NOTICE "Init spi pin mode!\n");
        gpio = ioremap(GPIO_BASE, SZ_16K);

/*	// SPI Slave is on GPIO 18..21 
	for (pin = 18; pin <= 21; pin++) {
		INP_GPIO(pin);		// set mode to GPIO input first 
		SET_GPIO_ALT(pin, 3);	// set mode to ALT 3 
	}*/
  reg = readl(gpio + 0x04);
  reg |= (0b111111 << 24);   //ALT3 for Pins 18 and 19
  writel(reg, gpio + 0x04);
  printk(KERN_NOTICE "FSEL1 Register : 0x%08lx \n", (unsigned long)reg);
  reg = readl(gpio + 0x08);
  reg |= 0b111111;           //ALT3 for Pins 20 ans 21
  writel(reg, gpio + 0x08);
  printk(KERN_NOTICE "FSEL2 Register : 0x%08lx \n", (unsigned long)reg);
	iounmap(gpio);

//#undef INP_GPIO
//#undef SET_GPIO_ALT
}



/****************************************************************************/
/* IRQ handler - fired on interrupt                                         */
/****************************************************************************/
static irqreturn_t controller_irq_handler(int irq, void *dev_id) {
 
   unsigned long flags;
   u32 mis;
   struct bcm2708_drive_controller_struct *drive_controller = dev_id;

   mis  = readl(drive_controller->base + SPI_MIS);
 /*  if( cs & SPI_CS_DONE){
 //     if(!drive_controller->len)
      cs &= ~(SPI_CS_INTR | SPI_CS_INTD | SPI_CS_TA);
      writel(cs, drive_controller->base);
   }*/ 

   local_irq_save(flags);              //disable hard interrupts;save in flag

   printk(KERN_NOTICE "Interrupt [%d] for device was triggered !.\n",
          irq);
 
   local_irq_restore(flags);          //restore interrupts
 
   return IRQ_HANDLED;
}
 
/****************************************************************************/
/*                      Module probe and remove block.                      */
/****************************************************************************/

static int bcm2708_drive_controller_probe(struct platform_device *pdev){
  struct bcm2708_drive_controller_struct *drive_controller;
  struct resource *regs;
  int irq, err;
  u32 reg = 0;

  printk(KERN_NOTICE "Enter drive controller probe method!\n");


  regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  if(!regs){
     dev_err(&pdev->dev, "could not get IO memory\n");
     return -ENXIO;
  }
  
  irq = platform_get_irq(pdev, 0);
  if(irq < 0){
     dev_err(&pdev->dev, "could not get IRQ\n");
     return irq;
  }


  bcm2708_init_spi_pinmode();

  drive_controller = kmalloc(sizeof(struct bcm2708_drive_controller_struct),
                             GFP_KERNEL);
  if(!drive_controller){
     dev_err(&pdev->dev, "could not allocate memory!\n");
     return -ENOMEM;
  }

  memset(drive_controller, 0, sizeof(struct bcm2708_drive_controller_struct));

  drive_controller->tx_buf = kmalloc(BUFFER_SIZE, GFP_KERNEL);

  if(!(drive_controller->tx_buf)){
     dev_err(&pdev->dev, "could not allocate memory!\n");
     return -ENOMEM;
  }
  memset(drive_controller->tx_buf, 0, BUFFER_SIZE);

  drive_controller->rx_buf = kmalloc(BUFFER_SIZE, GFP_KERNEL);

  if(!(drive_controller->rx_buf)){
     dev_err(&pdev->dev, "could not allocate memory!\n");
     return -ENOMEM;
  }
  memset(drive_controller->rx_buf, 0, BUFFER_SIZE);


  err = request_irq(irq, controller_irq_handler, 0, dev_name(&pdev->dev),
                    drive_controller);
  if(err){
     dev_err(&pdev->dev, "could not request IRQ: %d!\n", err);
     goto irq_fail;
  }

  drive_controller->irq = irq;

  drive_controller->base = ioremap(regs->start, resource_size(regs));
  if(!drive_controller->base){
     dev_err(&pdev->dev, "could not remap memory!\n");
//     goto remap_fail;
  }

  platform_set_drvdata(pdev, drive_controller);

 // reg = readl(drive_controller->base + SPI_IMSC);
  reg |= SPI_IMSC_RXIM;
  iowrite32(reg, drive_controller->base + SPI_IMSC);

  reg = 0;
  reg &= ~(SPI_CR_CPHA | SPI_CR_CPOL);
  reg |= (SPI_CR_SPI | SPI_CR_RXE | SPI_CR_TXE);

  iowrite32(reg, drive_controller->base + SPI_CR);
  reg |= (SPI_CR_EN);
  iowrite32(reg, drive_controller->base + SPI_CR);

  dev_info(&pdev->dev, "Drive Controller at 0x%08lx (irq %d)\n",
                       (unsigned long)regs->start, irq);

/* remap_fail:
//    free_irq(irq, 0);
*/
  irq_fail:

  return 0;
}

static int bcm2708_drive_controller_remove(struct platform_device *pdev){

  struct bcm2708_drive_controller_struct *drive_controller;

  printk(KERN_NOTICE "Drive controller remove method evoked!\n");
  drive_controller = platform_get_drvdata(pdev);

  kfree(drive_controller->tx_buf);
  kfree(drive_controller->rx_buf);
 
  free_irq(drive_controller->irq, drive_controller);
  kfree(drive_controller);
  platform_set_drvdata(pdev, NULL); 

  return 0;
}

/***************************************************************************/
/*                   sysfs interface to userspace                          */
/***************************************************************************/

static ssize_t send_value(struct device *dev, struct device_attribute *attr,
                          const char *buffer, size_t count){
 
  u32 reg;
  int value;
  struct bcm2708_drive_controller_struct *drive_controller;

  sscanf(buffer, "%d", &value);
  drive_controller = dev_get_drvdata(dev);

  printk(KERN_NOTICE "send value is %d\n", value);
  reg = readl(drive_controller->base + SPI_DR);
  printk(KERN_NOTICE "DR Register before send: 0x%08lx \n", (unsigned long)reg);
  writeb(value, drive_controller->base + SPI_DR);

  reg = readl(drive_controller->base + SPI_DR);
  printk(KERN_NOTICE "DR Register after send: 0x%08lx \n", (unsigned long)reg);
  
  reg = readl(drive_controller->base + SPI_CR);
  printk(KERN_NOTICE "CR Register is: 0x%08lx \n", (unsigned long)reg);

  return count;
}

DEVICE_ATTR(sendValue, 0644, NULL, send_value);

static struct attribute *drive_controller_attrs[] = {
  &dev_attr_sendValue.attr,
  NULL
};

static struct attribute_group drive_controller_attr_group = {
  .attrs = drive_controller_attrs,
};

/****************************************************************************/
/*                           platform specifics                             */
/*        resource and device definition should stand in bcm2708.c          */
/****************************************************************************/

static struct resource bcm2708_drive_controller_resources[] = {
         {
                   .start = SPI_SLAVE_BASE,
                   .end   = SPI_SLAVE_BASE + SZ_256 -1,
                   .flags = IORESOURCE_MEM,
         }, {
                   .start = IRQ_NUMBER,
                   .end   = IRQ_NUMBER,
                   .flags = IORESOURCE_IRQ,
         }
};


struct platform_device *drive_controller_device;

static struct platform_driver bcm2708_drive_controller_driver = {
        .driver          =  {
                .name    =  DRV_NAME,
                .owner   =  THIS_MODULE,
        },
        .probe           = bcm2708_drive_controller_probe,
        .remove          = bcm2708_drive_controller_remove,
};


/***************************************************************************/
/*                          controller-init                                */
/***************************************************************************/

int controller_init(void) {
 
  int retvalue; 

   drive_controller_device = platform_device_register_simple(DRV_NAME,0,
                                   bcm2708_drive_controller_resources, 2);
   if(IS_ERR(drive_controller_device)){
      printk(KERN_NOTICE "failed to register platform controller driver!\n");
      return 0;
   }

   retvalue = sysfs_create_group(&drive_controller_device->dev.kobj, 
                      &drive_controller_attr_group);
   if(retvalue){
        printk(KERN_NOTICE "Unable to create group for  controller_driver\n");
        platform_device_unregister(drive_controller_device);
        return -ENOMEM;
   }


   retvalue = platform_driver_register(&bcm2708_drive_controller_driver);

   if(retvalue){
        printk(KERN_NOTICE "Unable to register controller_driver\n");
        platform_device_unregister(drive_controller_device);
   }

   return 0;
}
 
void controller_cleanup(void) {
   printk(KERN_NOTICE "spi interrupt handler module exit\n");
   sysfs_remove_group(&drive_controller_device->dev.kobj, 
                      &drive_controller_attr_group);
   platform_device_unregister(drive_controller_device);
   platform_driver_unregister(&bcm2708_drive_controller_driver);

   return;
}
 
 
module_init(controller_init);
module_exit(controller_cleanup);
 
 
/****************************************************************************/
/* Module licensing/description block.                                      */
/****************************************************************************/

MODULE_LICENSE("GPL");
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_ALIAS("platform:" DRV_NAME);
Hi Hendric,
Did you alread made the Pi2 as SPI slave? I would need some help from you in configuring Pi as SPI slave. Your support will be really helpful for me.
Thank you, Krish

Return to “Interfacing (DSI, CSI, I2C, etc.)”