#pragma once #include #include // CAUTION: DO NOT MODIFY REGISTERS FROM PRU unless you can be // absolutely certain that linux will not modify the register around the // same time, otherwise you'll create a race condition that may randomly // cause register writes to be lost. // // The only exceptions are CLEARDATAOUT and SETDATAOUT which are // write-only registers that perform atomic operations on the DATAOUT // register and are therefore safe for concurrent use by pru and linux. // (This also applies to IRQSTATUS_SET/CLR but obviously you shouldn't // mess with interrupt handling registers used by linux, with or without // race condition.) // typedef struct { /*000*/ uint32_t volatile REVISION; /*004*/ uint32_t volatile rsvd004[(0x010-0x004)/4]; /*010*/ uint32_t volatile SYSCONFIG; /*014*/ uint32_t volatile rsvd014[(0x020-0x014)/4]; /*020*/ uint32_t volatile EOI; /*024*/ uint32_t volatile IRQSTATUS_RAW[2]; /*02c*/ uint32_t volatile IRQSTATUS[2]; /*034*/ uint32_t volatile IRQSTATUS_SET[2]; /*03c*/ uint32_t volatile IRQSTATUS_CLR[2]; /*044*/ uint32_t volatile IRQWAKEN[2]; /*04c*/ uint32_t volatile rsvd04c[(0x114-0x04c)/4]; /*114*/ uint32_t volatile SYSSTATUS; /*118*/ uint32_t volatile rsvd118[(0x130-0x118)/4]; /*130*/ uint32_t volatile CTRL; /*134*/ uint32_t volatile OE; /*138*/ uint32_t volatile DATAIN; /*13c*/ uint32_t volatile DATAOUT; /*140*/ uint32_t volatile LEVELDETECT0; /*144*/ uint32_t volatile LEVELDETECT1; /*148*/ uint32_t volatile RISINGDETECT; /*14c*/ uint32_t volatile FALLINGDETECT; /*150*/ uint32_t volatile DEBOUNCENABLE; /*154*/ uint32_t volatile DEBOUNCINGTIME; /*158*/ uint32_t volatile rsvd158[(0x190-0x158)/4]; /*190*/ uint32_t volatile CLEARDATAOUT; /*194*/ uint32_t volatile SETDATAOUT; } sysGpio; #define GPIO0 (*(sysGpio *)0x44e07000) #define GPIO1 (*(sysGpio *)0x4804c000) #define GPIO2 (*(sysGpio *)0x481ac000) #define GPIO3 (*(sysGpio *)0x481ae000) //------------------ Safe wrapper functions --------------------------------------------------- // // The first argument must always be one of: &GPIO0, &GPIO1, &GPIO2, &GPIO3. // // For efficiency you can act on multiple gpios of one controller at the same time, with the // 32 gpios of one controller represented by the bits of an uint32_t. Convenience wrappers // that act on a single gpio are also provided further down. // // It is unsafe to change gpio direction from PRU so I'm not making a wrapper for that, set the // gpio direction from linux instead. Output values of gpios configured as input are ignored. // read all gpios of one gpio controller. static inline uint32_t gpio_read( sysGpio *dev ) { return dev->DATAIN; } // set output value to 0 for one or more gpios of one gpio controller. static inline void gpio_set_low( sysGpio *dev, uint32_t mask ) { dev->CLEARDATAOUT = mask; } // set output value to 1 for one or more gpios of one gpio controller. static inline void gpio_set_high( sysGpio *dev, uint32_t mask ) { dev->SETDATAOUT = mask; } // combines gpio_set_low() and gpio_set_high(), but optimized to use only a single bus write. // this minimizes the delay between the two actions. static inline void gpio_set_low_set_high( sysGpio *dev, uint32_t low_mask, uint32_t high_mask ) { *(uint64_t volatile *)&dev->CLEARDATAOUT = low_mask | (uint64_t)high_mask << 32; } // set output value for one or more gpios of one gpio controller, with value specified per gpio. static inline void gpio_set( sysGpio *dev, uint32_t mask, uint32_t values ) { gpio_set_low_set_high( dev, mask & ~values, mask & values ); } // set output value for one or more gpios of one gpio controller, using same value for all. static inline void gpio_fill( sysGpio *dev, uint32_t mask, bool value ) { (&dev->CLEARDATAOUT)[ value ] = mask; } // Convenience wrappers for accessing a single gpio (0..31) of a gpio controller: // read one gpio static inline bool gpio_read_one( sysGpio *dev, uint8_t gpio ) { return ( gpio_read( dev ) >> gpio ) & 1; } // set output value of one gpio to 0 static inline void gpio_set_one_low( sysGpio *dev, uint8_t gpio ) { gpio_set_low( dev, 1u << gpio ); } // set output value of one gpio to 1 static inline void gpio_set_one_high( sysGpio *dev, uint8_t gpio ) { gpio_set_high( dev, 1u << gpio ); } // set output value of one gpio static inline void gpio_set_one( sysGpio *dev, uint8_t gpio, bool value ) { gpio_fill( dev, 1u << gpio, value ); }