element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet & Tria Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • About Us
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      • Japan
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Vietnam
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
Raspberry Pi
  • Products
  • More
Raspberry Pi
Raspberry Pi Forum Driver fixes and updates to kernel 3.18.16 and 4.0.5
  • Blog
  • Forum
  • Documents
  • Quiz
  • Events
  • Polls
  • Files
  • Members
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
Join Raspberry Pi to participate - click to join for free!
Featured Articles
Announcing Pi
Technical Specifications
Raspberry Pi FAQs
Win a Pi
Raspberry Pi Wishlist
Actions
  • Share
  • More
  • Cancel
Forum Thread Details
  • Replies 180 replies
  • Subscribers 689 subscribers
  • Views 23058 views
  • Users 0 members are here
  • raspberry_pi
  • raspeberry_pi_accessories
Related

Driver fixes and updates to kernel 3.18.16 and 4.0.5

hiassoft
hiassoft over 10 years ago

Edit: Current kernel versions and install/config instructions are also available from my webpage http://www.horus.com/~hias/cirrus-driver.html

 

During the last few weeks I fixed various issues in the Wolfson/Cirrus driver and rebased it so it works with the current RPi kernel versions (3.18.16 and 4.0.5).

 

You can download the patches from my GitHub repository. The 3.18 kernel with Cirrus drivers is in the cirrus-3.18.y branch, the 4.0 kernel with Cirrus drivers is in the cirrus-4.0.y branch. I'll rebase and update these branches from time to time so that the Cirrus driver and my changes will stay on top of the commit list.

 

If you just want to have an updated 3.18.16 kernel you can download precompiled binaries from here. Just unpack the tarball in the root directory. Before you do that it might be a good idea to update the firmware files (bootcode.bin, start*.elf and fixup*.dat in the boot directory) to the latest version.

 

Here's a list of my changes:

- Added the FLL1 setup back so that switching between 44.1kHz and 48kHz (and other sample rates) works fine.

- Don't register Arizona IRQ if it's set to 0. The Cirrus driver uses polling here and if we register an interrupt handler for irq 0 we get lots of "spurious interrupt" messages spamming dmesg in kernel 3.19 and newer. IRQ 0 is wrong anyway.

- Include DCVDD patches from the Cirrus linux-drivers repository. These patches make sure the WM8804 chip is initialized properly. Without this patch I sometimes had SPDIF audio out only on the right channel.

- Disable spidev0 in Cirrus device tree overlay. That's mainly a safety precaution so that userspace programs trying to access spi0.0 won't interfere with the WM8804 reset line. I'm not 100% sure this is needed at all, so maybe I'll remove it some time later.

 

And some important notes:

I haven't included the mmap patch, this is already supported in the upstream kernels but currently disabled by default. To enable mmap support add the following line to config.txt:

dtoverlay=i2s-mmap

 

If you compile the kernel on your own please note that the devicetree overlays have now been moved to arch/arm/boot/dts/overlays.

 

Kernel 4.0 now uses spi_bcm2835 by default (the older spi_bcm2708 module is available via a devicetree overlay) so you have to extend your /etc/modprobe.d conf file and add a pre-depend for spi_bcm2835 as well. It's safe to have both the old and the new module in here, so just use this configuration:

softdep arizona-spi pre: arizona-ldo1
softdep spi-bcm2708 pre: fixed
softdep spi-bcm2835 pre: fixed

 

so long,

 

Hias

  • Sign in to reply
  • Cancel
Parents
  • Former Member
    Former Member over 10 years ago

    Hi Hias,

     

    This is a little bit off topic, but I am now trying to access the registers on the WM5102 so that I can use the cirrus logic card as a real time audio processing box (takes input from line in, processes audio in C, passes output through line out). I am trying to do it using i2c with the help of wiring pi. Here is the code I have as well as the output when running it. Is there something additional that I have to do to get i2c working with the cirrus card that I am missing?

     

    #include <stdio.h>

    #include <wiringPiI2C.h>

     

    int main()

    {

       int fd = wiringPiI2CSetup(26);

       int test1 = wiringPiI2CReadReg8(fd,768);

       int test2 = wiringPiI2CWriteReg8(fd,768,16);

       int test3 = wiringPiI2CReadReg8(fd,768);

       printf("fd = %i, test1 = %i, test2 = %i, test3 = %i\n", fd, test1, test2, test3);

       return 0;

    }

     

    it prints: "fd = 3, test1 = 0, test2 = 0 test3 = 0"

     

    Thanks for any help,


    Ryan

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Cancel
  • hiassoft
    hiassoft over 10 years ago in reply to Former Member

    Hi Ryan!

    This is a little bit off topic, but I am now trying to access the registers on the WM5102 so that I can use the cirrus logic card as a real time audio processing box (takes input from line in, processes audio in C, passes output through line out). I am trying to do it using i2c with the help of wiring pi. Here is the code I have as well as the output when running it. Is there something additional that I have to do to get i2c working with the cirrus card that I am missing?

    So far I didn't have much luch talking to the wm5102 via I2C. I tried it with the standard /dev/i2c interface (I2C_RDWR ioctl, 32 bits register address and 16 bit data).

     

    Changing the devicetree overlay and hooking up the wm5102 to i2c address 0x1a didn't work either, it detected the wm5102 via I2C but couldn't apply the hardware patch. I2C reads from the wm5102 always seem to return 0x5102. Not sure what's going on here, maybe I missed something.

     

    Even if I2C access in parallel to SPI access would work it would mess things up with the kernel driver. It uses the regmap/regcache layer and if that's out of sync with the real register values (changed behind it's back via I2C) that could lead to interesting results...

     

    The question is: what do you want to do and do you really have to access the chip-registers directly? Most of the chip's internal registers are exposed via alsa mixer controls and for standard realtime processing you should be fine using the userspace alsa interface.

     

    so long,

     

    Hias

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Cancel
  • Former Member
    Former Member over 10 years ago in reply to hiassoft

    Hi Hias,

     

    Okay, I don't have much experience using alsa. I am working on a reverberation effect to be used with guitar. I need to take the guitar signal from line input one sample at a time, put it through some C code that I have already finished, and then put the new sample back out of line out. Will that be possible using alsa? Also I'll probably want to change the sampling rate and bps. If it is possible, will I be using alsa outside of the C program I have written?

     

    Thanks again,

     

    Ryan

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Cancel
  • hiassoft
    hiassoft over 10 years ago in reply to Former Member

    Hi Ryan!

    Okay, I don't have much experience using alsa. I am working on a reverberation effect to be used with guitar. I need to take the guitar signal from line input one sample at a time, put it through some C code that I have already finished, and then put the new sample back out of line out. Will that be possible using alsa? Also I'll probably want to change the sampling rate and bps. If it is possible, will I be using alsa outside of the C program I have written?

    That depends on your program image

     

    Using alsa (as it's the native linux audio layer) is just one of the possiblities. Some people prefer using jack (which then interfaces to alsa) and there are even very high level applications like PD (pure data) that allow you to create realtime effects.

     

    Just do some googling and choose the solution that meets your requirements best.

     

    so long,

     

    Hias

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Cancel
  • gkzsolt
    gkzsolt over 10 years ago in reply to hiassoft

    Hi Matthias,

     

    So far I didn't have much luch talking to the wm5102 via I2C. I tried it with the standard /dev/i2c interface (I2C_RDWR ioctl, 32 bits register address and 16 bit data).

     

    Changing the devicetree overlay and hooking up the wm5102 to i2c address 0x1a didn't work either, it detected the wm5102 via I2C but couldn't apply the hardware patch. I2C reads from the wm5102 always seem to return 0x5102. Not sure what's going on here, maybe I missed something.

    Not sure that it is related to this, but do you know about the incomplete implementation of the I2C protocol on RPI? Specifically, the "repeated starts read" was not supported by the i2c driver about one year ago. I found this quite painfully, after dispairing in not being able to communicate with my MPR121 chip (but working with no problems on Arduino). After getting the same bad answer from a register I found this article: https://jjackowski.wordpress.com/2013/07/13/i2c-repeated-starts-implemented-on-the-raspberry-pi/

     

    They might be fixed this in the meantime (in the master), I don't know: I decided to refrain from doing any I2C (or even SPI) task with the Raspberry (it was a big shock for me and I think it's a shame, mainly because it is not mentioned anywhere.) But I guess there are a few patched drivers around, if one searches carefully (also mentioned in the article). If you know anything, let me know.

     

    Cheers,

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • Cancel
  • hiassoft
    hiassoft over 10 years ago in reply to gkzsolt

    Hi Zsolt!

    Not sure that it is related to this, but do you know about the incomplete implementation of the I2C protocol on RPI? Specifically, the "repeated starts read" was not supported by the i2c driver about one year ago.

    Excellent info, this was exactly the part I was missing!

     

    The wm5102 register read operation needs a repeated start, and fortunately it's possible to make it working by enabling combined transactions in the bcm2708 I2C driver

     

    options i2c-bcm2708 combined=1

     

    If anyone's interested here's the (now working) C code I used to read/write the wm5102 registers.

     

    /*
    * cirrus-reg - access wm5102 registers via i2c
    *
    * Copyright (C) 2015 Matthias Reichl <hias@horus.com>
    *
    * This program is free software; you can redistribute it and/or
    * modify it under the terms of the GNU General Public License
    * version 2 as published by the Free Software Foundation.
    *
    * This program is distributed in the hope that it will be useful, but
    * WITHOUT ANY WARRANTY; without even the implied warranty of
    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    * General Public License for more details.
    */
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <sys/ioctl.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <linux/i2c.h>
    #include <linux/i2c-dev.h>
    
    static const char* i2cdev = "/dev/i2c-1";
    static const int i2caddr = 0x1a;
    
    int main(int argc, char** argv)
    {
        int f;
        int ret = 0;
        int reg;
        int value;
        int wrmode = 1;
        // buffer for 4-byte register address plus 2 byte register data
        unsigned char buf[6];
        // I2C messages:
        // reading register needs 2 messages with repeated start,
        // writing register sends 1 message with data+value
        struct i2c_msg msgs[2];
        struct i2c_rdwr_ioctl_data rdwr_data;
    
        if (argc < 2 || argc > 3) {
            goto usage;
        }
    
        // first 4 bytes of buffer are register address in big endian format
        reg = strtol(argv[1], NULL, 0);
        buf[0] = (reg >> 24) & 0xff;
        buf[1] = (reg >> 16) & 0xff;
        buf[2] = (reg >> 8) & 0xff;
        buf[3] = reg & 0xff;
    
        // default setup: 1 i2c message for write
        rdwr_data.msgs = &msgs[0];
        rdwr_data.nmsgs = 1;
    
        // first message: write 6 bytes
        msgs[0].addr = i2caddr;
        msgs[0].flags = 0;
        msgs[0].buf = &buf[0];
        msgs[0].len = 6;
    
        if (argc == 3) {
            // write register case, store value in buffer
            value = strtol(argv[2], NULL, 0);
            buf[4] = (value >> 8) & 0xff;
            buf[5] = value & 0xff;
        } else {
            wrmode = 0;
            // only transfer 4 bytes in first message
            msgs[0].len = 4;
            // second message, read 2 bytes into buf+4
            msgs[1].addr = i2caddr;
            msgs[1].flags = I2C_M_RD;
            msgs[1].buf = &buf[4];
            msgs[1].len = 2;
            rdwr_data.nmsgs = 2;
        }
    
        f = open(i2cdev, O_RDWR);
        if (f < 0) {
            printf("cannot open i2c device %s\n", i2cdev);
            return 1;
        }
    
        if ((ret = ioctl(f, I2C_RDWR, &rdwr_data)) < 0) {
            perror("I2C_RDWR");
            return ret;
        }
    
        if (wrmode) {
            printf("%06x <= %04x\n", reg, value);
        } else {
            value = (buf[4] << 8) | buf[5];
            printf("%06x: %04x\n", reg, value);
        }
        close(f);
        return 0;
    
    usage:
        printf("RPi Cirrus sound card direct register access via i2c\n");
        printf("(c) 2015 Matthias Reichl <hias@horus.com>\n\n");
        printf("usage: cirrus-reg REGISTER        to read a register\n");
        printf("   or: cirrus-reg REGISTER VALUE  to write to a register\n\n");
        printf("eg:\n");
        printf("cirrus-reg 0xc02\n");
        printf("cirrus-reg 0xc02 0xa101\n\n");
        printf("note: combined transactions need to be enabled in i2c-bcm2708!\n");
    
        return 1;
    }

     

    so long,

     

    Hias

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Cancel
  • gkzsolt
    gkzsolt over 10 years ago in reply to hiassoft

    Hi Matthias,

     

    This is awesome (and that you figured it out)! Just a lame question: where should I put the driver options (maybe in /etc/modules)? Sorry...

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Cancel
  • hiassoft
    hiassoft over 10 years ago in reply to gkzsolt

    Hi Zsolt!

    This is awesome (and that you figured it out)! Just a lame question: where should I put the driver options (maybe in /etc/modules)? Sorry...

    Put them in a *.conf file inside /etc/modprobe.d - I choose /etc/modprobe.d/i2c-combined.conf for that setting.

     

    The combined transfer functionality in the kernel is similar to the code in the link you posted, but supports a wider range of I2C transfers (first message may be up to 16 bytes).

     

    so long,

     

    Hias

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Cancel
Reply
  • hiassoft
    hiassoft over 10 years ago in reply to gkzsolt

    Hi Zsolt!

    This is awesome (and that you figured it out)! Just a lame question: where should I put the driver options (maybe in /etc/modules)? Sorry...

    Put them in a *.conf file inside /etc/modprobe.d - I choose /etc/modprobe.d/i2c-combined.conf for that setting.

     

    The combined transfer functionality in the kernel is similar to the code in the link you posted, but supports a wider range of I2C transfers (first message may be up to 16 bytes).

     

    so long,

     

    Hias

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Cancel
Children
No Data
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2026 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube