/* * \brief Gpio driver for the RaspberryPI * \author Reinier Millo Sánchez * \author Alexy Gallardo Segura * \author Humberto Lopéz Leon * \date 2015-07-23 */ /* * Copyright (C) 2012 Ksys Labs LLC * Copyright (C) 2012-2017 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. */ #ifndef _DRIVERS__GPIO__SPEC__RPI__GPIO_H_ #define _DRIVERS__GPIO__SPEC__RPI__GPIO_H_ /* Genode includes */ #include #include #include namespace Gpio { using namespace Genode; class Reg; } class Gpio::Reg : Attached_io_mem_dataspace, Mmio { private: /** * GPIO Function Select Registers */ struct Gpfsel : Register_array <0x00,32,6,32> { struct Sel0 : Bitfield <0,3> {}; struct Sel1 : Bitfield <3,3> {}; struct Sel2 : Bitfield <6,3> {}; struct Sel3 : Bitfield <9,3> {}; struct Sel4 : Bitfield <12,3> {}; struct Sel5 : Bitfield <15,3> {}; struct Sel6 : Bitfield <18,3> {}; struct Sel7 : Bitfield <21,3> {}; struct Sel8 : Bitfield <24,3> {}; struct Sel9 : Bitfield <27,3> {}; }; /** * GPIO Pin Output Set Registers */ struct Gpset : Register_array <0x1c,32,64,1> {}; /** * GPIO Pin Output Clear Registers */ struct Gpclr : Register_array <0x28,32,64,1> {}; /** * GPIO Pin Level Registers */ struct Gplev : Register_array <0x34,32,64,1> {}; /** * GPIO Pin Event Detect Status Registers */ struct Gppeds : Register_array <0x40,32,64,1> {}; struct Gppeds_raw : Register <0x40,64> {}; /** * GPIO Pin Rising Edge Detect Enable Registers */ struct Gpren : Register_array <0x4c,32,64,1> {}; /** * GPIO Pin Falling Edge Detect Enable Registers */ struct Gpfen : Register_array <0x58,32,64,1> {}; /** * GPIO Pin High Detect Enable Registers */ struct Gphen : Register_array <0x64,32,64,1> {}; /** * GPIO Pin Low Detect Enable Registers */ struct Gplen : Register_array <0x70,32,64,1> {}; /** * GPIO Pin Aync. Rising Edge Detect Registers */ struct Gparen : Register_array <0x7c,32,64,1> {}; /** * GPIO Pin Async. Falling Edge Detect Registers */ struct Gpafen : Register_array <0x88,32,64,1> {}; /** * GPIO Pin Pull-up/down Enable Registers */ struct Gppud : Register <0x94,32> {}; /** * GPIO Pin Pull-up/down Enable Clock Registers */ struct Gppudclk : Register_array <0x98,32,64,1> {}; struct Timer_delayer : Timer::Connection, Mmio::Delayer { Timer_delayer(Genode::Env &env) : Timer::Connection(env) { } /** * Implementation of 'Delayer' interface */ void usleep(uint64_t us) override { Timer::Connection::usleep(us); } } _delayer; template void _set_gpio_det(unsigned gpio) { write(0, gpio); write(0, gpio); write(0, gpio); write(0, gpio); write(0, gpio); write(1, gpio); } public: Reg(Genode::Env &env, addr_t base, off_t offset, size_t size) : Attached_io_mem_dataspace(env, base, size), Mmio((addr_t)local_addr() + offset), _delayer(env) { } enum Function { FSEL_INPUT = 0, FSEL_OUTPUT = 1, FSEL_ALT0 = 4, FSEL_ALT1 = 5, FSEL_ALT2 = 6, FSEL_ALT3 = 7, FSEL_ALT4 = 3, FSEL_ALT5 = 2, }; void set_gpio_function(unsigned gpio, Function function) { /* * Set a pull-up internal resistor in the input pin to avoid * electromagnetic radiation or static noise */ if (function == FSEL_INPUT) { write(1); _delayer.usleep(1); write(1, gpio); _delayer.usleep(1); write(0); write(0, gpio); } /* set the pin function */ unsigned sel_id = gpio % 10; unsigned reg_id = gpio / 10; switch(sel_id){ case 0: write(function, reg_id); break; case 1: write(function, reg_id); break; case 2: write(function, reg_id); break; case 3: write(function, reg_id); break; case 4: write(function, reg_id); break; case 5: write(function, reg_id); break; case 6: write(function, reg_id); break; case 7: write(function, reg_id); break; case 8: write(function, reg_id); break; case 9: write(function, reg_id); break; default:; } } unsigned get_gpio_function(unsigned gpio) { unsigned sel_id = gpio % 10; unsigned reg_id = gpio / 10; switch(sel_id){ case 0: return read(reg_id); case 1: return read(reg_id); case 2: return read(reg_id); case 3: return read(reg_id); case 4: return read(reg_id); case 5: return read(reg_id); case 6: return read(reg_id); case 7: return read(reg_id); case 8: return read(reg_id); case 9: return read(reg_id); default: return 0; } } int get_gpio_level(unsigned gpio) { return read(gpio); } void set_gpio_level(unsigned gpio) { write(1, gpio); } void clear_gpio_level(unsigned gpio) { write(1, gpio); } void set_gpio_falling_detect(unsigned gpio) { _set_gpio_det(gpio); } void set_gpio_rising_detect(unsigned gpio) { _set_gpio_det(gpio); } void set_gpio_high_detect(unsigned gpio) { _set_gpio_det(gpio); } void set_gpio_low_detect(unsigned gpio) { _set_gpio_det(gpio); } void set_gpio_async_falling_detect(unsigned gpio) { _set_gpio_det(gpio); } void set_gpio_async_rising_detect(unsigned gpio) { _set_gpio_det(gpio); } template void for_each_gpio_status(F f) { Gppeds_raw::access_t const gppeds = read(); for(unsigned i = 0; i < Gppeds_raw::ACCESS_WIDTH; i++) { f(i, gppeds & (1 << i)); } } void clear_event(unsigned gpio) { write(1, gpio); } }; #endif /* _DRIVERS__GPIO__SPEC__RPI__GPIO_H_ */