diff --git a/os/include/gpio_session/capability.h b/os/include/gpio_session/capability.h new file mode 100644 index 0000000000..abb3eceba5 --- /dev/null +++ b/os/include/gpio_session/capability.h @@ -0,0 +1,23 @@ +/* + * \brief Gpio session capability type + * \author Ivan Loskutov + * \date 2012-06-23 + */ + +/* + * Copyright (C) 2012 Ksys Labs LLC + * Copyright (C) 2012 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#ifndef _INCLUDE__GPIO_SESSION__CAPABILITY_H_ +#define _INCLUDE__GPIO_SESSION__CAPABILITY_H_ + +#include +#include + +namespace Gpio { typedef Genode::Capability Session_capability; } + +#endif /* _INCLUDE__GPIO_SESSION__CAPABILITY_H_ */ diff --git a/os/include/gpio_session/client.h b/os/include/gpio_session/client.h new file mode 100644 index 0000000000..effe3b8b68 --- /dev/null +++ b/os/include/gpio_session/client.h @@ -0,0 +1,81 @@ +/* + * \brief Client-side Gpio session interface + * \author Ivan Loskutov + * \date 2012-06-23 + */ + +/* + * Copyright (C) 2012 Ksys Labs LLC + * Copyright (C) 2012 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#ifndef _INCLUDE__GPIO_SESSION_H__CLIENT_H_ +#define _INCLUDE__GPIO_SESSION_H__CLIENT_H_ + +#include +#include + +namespace Gpio { + + struct Session_client : Genode::Rpc_client + { + explicit Session_client(Session_capability session) + : Genode::Rpc_client(session) { } + + + void direction_output(int gpio, bool enable) + { + call(gpio, enable); + } + + void direction_input(int gpio) + { + call(gpio); + } + + void dataout(int gpio, bool enable) + { + call(gpio, enable); + } + + int datain(int gpio) + { + return call(gpio); + } + + void debounce_enable(int gpio, bool enable) + { + call(gpio, enable); + } + + void debouncing_time(int gpio, unsigned int us) + { + call(gpio, us); + } + + void falling_detect(int gpio, bool enable) + { + call(gpio, enable); + } + + void rising_detect(int gpio, bool enable) + { + call(gpio, enable); + } + + void irq_enable(int gpio, bool enable) + { + call(gpio, enable); + } + + void irq_sigh(Signal_context_capability cap, int gpio) + { + call(cap, gpio); + } + }; +} + +#endif /* _INCLUDE__GPIO_SESSION_H__CLIENT_H_ */ \ No newline at end of file diff --git a/os/include/gpio_session/connection.h b/os/include/gpio_session/connection.h new file mode 100644 index 0000000000..a77daf2943 --- /dev/null +++ b/os/include/gpio_session/connection.h @@ -0,0 +1,33 @@ +/* + * \brief Connection to Gpio session + * \author Ivan Loskutov + * \date 2012-06-23 + */ + +/* + * Copyright (C) 2012 Ksys Labs LLC + * Copyright (C) 2012 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#ifndef _INCLUDE__GPIO_SESSION__CONNECTION_H_ +#define _INCLUDE__GPIO_SESSION__CONNECTION_H_ + +#include +#include + +namespace Gpio { + + struct Connection : Genode::Connection, Session_client + { + Connection() + : + Genode::Connection(session("ram_quota=4K")), + Session_client(cap()) + { } + }; +} + +#endif /* _INCLUDE__GPIO_SESSION__CONNECTION_H_ */ diff --git a/os/include/gpio_session/gpio_session.h b/os/include/gpio_session/gpio_session.h new file mode 100644 index 0000000000..eda08624e5 --- /dev/null +++ b/os/include/gpio_session/gpio_session.h @@ -0,0 +1,147 @@ +/* + * \brief Gpio session interface + * \author Ivan Loskutov + * \date 2012-06-23 + */ + +/* + * Copyright (C) 2012 Ksys Labs LLC + * Copyright (C) 2012 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#ifndef _INCLUDE__GPIO_SESSION__GPIO_SESSION_H_ +#define _INCLUDE__GPIO_SESSION__GPIO_SESSION_H_ + +#include +#include +#include + +namespace Gpio { + + using namespace Genode; + + struct Session : Genode::Session + { + static const char *service_name() { return "Gpio"; } + + virtual ~Session() { } + + /** + * Configure direction on a specified GPIO pin as output + * + * \param gpio number of the pin + * \param enable logic level on the pin + */ + virtual void direction_output(int gpio, bool enable) = 0; + + /** + * Configure direction on a specified GPIO pin as input + * + * \param gpio number of the pin + */ + virtual void direction_input(int gpio) = 0; + + /** + * Set the logic level on a specified GPIO pin + * + * \param gpio number of the pin + * \param enable logic level on the pin + */ + virtual void dataout(int gpio, bool enable) = 0; + + /** + * Read the logic level on a specified GPIO pin + * + * \param gpio number of the pin + * + * \return level on specified GPIO pin + */ + virtual int datain(int gpio) = 0; + + /** + * Enable the debounce on a specified input GPIO pin + * + * \param gpio number of the pin + */ + virtual void debounce_enable(int gpio, bool enable) = 0; + + /** + * Set the debouncing time for all input pins of GPIO bank + * + * \param gpio number of the pin + */ + virtual void debouncing_time(int gpio, unsigned int us) = 0; + + /** + * Configure the interrupt request on occurence of a falling edge on + * a specified input GPIO pin + * + * \param gpio number of the pin + */ + virtual void falling_detect(int gpio, bool enable) = 0; + + /** + * Configure the interrupt request on occurence of a rising edge on + * a specified input GPIO pin + * + * \param gpio number of the pin + */ + virtual void rising_detect(int gpio, bool enable) = 0; + + /** + * Enable or disable the interrupt on a specified GPIO pin + * + * \param gpio number of the pin + * \param enable interrupt status( true - enable, false - disable) + */ + virtual void irq_enable(int gpio, bool enable) = 0; + + /** + * Register signal handler to be notified on interrupt on a specified + * GPIO pin + * + * \param cap capability of signal-context to handle GPIO + * interrupt + * \param gpio number of the pin + * + * This function is used for a set up signal handler for a specified + * GPIO interrupt. Signal emited to the client if IRQ on pin configured + * when the driver handles this IRQ. + */ + virtual void irq_sigh(Signal_context_capability cap, int gpio) = 0; + + /******************* + ** RPC interface ** + *******************/ + + GENODE_RPC(Rpc_direction_output, void, direction_output, int, bool); + GENODE_RPC(Rpc_direction_input, void, direction_input, int); + GENODE_RPC(Rpc_dataout, void, dataout, int, bool); + GENODE_RPC(Rpc_datain, int, datain, int); + GENODE_RPC(Rpc_debounce_enable, void, debounce_enable, int, bool); + GENODE_RPC(Rpc_debouncing_time, void, debouncing_time, int, unsigned int); + GENODE_RPC(Rpc_falling_detect, void, falling_detect, int, bool); + GENODE_RPC(Rpc_rising_detect, void, rising_detect, int, bool); + GENODE_RPC(Rpc_irq_enable, void, irq_enable, int, bool); + GENODE_RPC(Rpc_irq_sigh, void, irq_sigh, Signal_context_capability, int); + + + typedef Meta::Type_tuple + > > > > > > > > > Rpc_functions; + }; +} + +#endif /* _INCLUDE__GPIO_SESSION__GPIO_SESSION_H_ */ diff --git a/os/run/gpio_drv.run b/os/run/gpio_drv.run new file mode 100644 index 0000000000..3ac4f149af --- /dev/null +++ b/os/run/gpio_drv.run @@ -0,0 +1,74 @@ +# +# Build +# +if {[have_spec omap4] == 0} { + puts "Runs on OMAP4 only" + exit 0 +} + +set build_components { + core init + drivers/timer drivers/gpio + test/gpio_drv +} + +build $build_components + +create_boot_directory + +# +# Generate config +# + +append config { + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +} + +install_config $config + +# +# Boot modules +# + +# generic modules +set boot_modules { + core init + timer + omap4_gpio_drv + test-omap4_gpio_drv +} + +build_boot_image $boot_modules + diff --git a/os/src/drivers/gpio/omap4/driver.h b/os/src/drivers/gpio/omap4/driver.h new file mode 100644 index 0000000000..00908fe023 --- /dev/null +++ b/os/src/drivers/gpio/omap4/driver.h @@ -0,0 +1,448 @@ +/* + * \brief Gpio driver for the OMAP4 + * \author Ivan Loskutov + * \date 2012-06-23 + */ + +/* + * Copyright (C) 2012 Ksys Labs LLC + * Copyright (C) 2012 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#ifndef _DRIVER_H_ +#define _DRIVER_H_ + +/* Genode includes */ +#include +#include +#include +#include + +/* local includes */ +#include "gpio.h" + + +namespace Gpio { + using namespace Genode; + class Driver; +} + +static int verbose = 0; + +class Gpio::Driver +{ + public: + enum { + GPIO1_IRQ = 29 + 32, + GPIO2_IRQ = 30 + 32, + GPIO3_IRQ = 31 + 32, + GPIO4_IRQ = 32 + 32, + GPIO5_IRQ = 33 + 32, + GPIO6_IRQ = 34 + 32, + }; + + private: + + struct Timer_delayer : Timer::Connection, Mmio::Delayer + { + /** + * Implementation of 'Delayer' interface + */ + void usleep(unsigned us) + { + /* polling */ + if (us == 0) + return; + + unsigned ms = us / 1000; + if (ms == 0) + ms = 1; + + Timer::Connection::msleep(ms); + } + } _delayer; + + /* memory map */ + enum { + GPIO1_MMIO_BASE = 0x4a310000, + GPIO1_MMIO_SIZE = 0x1000, + + GPIO2_MMIO_BASE = 0x48055000, + GPIO2_MMIO_SIZE = 0x1000, + + GPIO3_MMIO_BASE = 0x48057000, + GPIO3_MMIO_SIZE = 0x1000, + + GPIO4_MMIO_BASE = 0x48059000, + GPIO4_MMIO_SIZE = 0x1000, + + GPIO5_MMIO_BASE = 0x4805b000, + GPIO5_MMIO_SIZE = 0x1000, + + GPIO6_MMIO_BASE = 0x4805d000, + GPIO6_MMIO_SIZE = 0x1000, + + NR_GPIOS = 6, + MAX_GPIOS = 192, + }; + + + Attached_io_mem_dataspace _gpio1_mmio; + Gpio_reg _gpio1; + Attached_io_mem_dataspace _gpio2_mmio; + Gpio_reg _gpio2; + Attached_io_mem_dataspace _gpio3_mmio; + Gpio_reg _gpio3; + Attached_io_mem_dataspace _gpio4_mmio; + Gpio_reg _gpio4; + Attached_io_mem_dataspace _gpio5_mmio; + Gpio_reg _gpio5; + Attached_io_mem_dataspace _gpio6_mmio; + Gpio_reg _gpio6; + + Gpio_reg *_gpio_bank[NR_GPIOS]; + + bool irq_enabled[MAX_GPIOS]; + + Signal_context_capability _sign[MAX_GPIOS]; + + public: + + Driver(); + + bool set_gpio_direction(int gpio, bool is_input); + bool set_gpio_dataout(int gpio, bool enable); + int get_gpio_datain(int gpio); + bool set_gpio_debounce_enable(int gpio, bool enable); + bool set_gpio_debouncing_time(int gpio, unsigned int us); + bool set_gpio_falling_detect(int gpio, bool enable); + bool set_gpio_rising_detect(int gpio, bool enable); + bool set_gpio_irq_enable(int gpio, bool enable); + + void register_signal(Signal_context_capability cap, int gpio) + { + if (!_sign[gpio].valid()) + { + _sign[gpio] = cap; + } + } + + void handle_event(int irq_number); + + private: + Gpio_reg *_get_gpio_bank(int gpio) { return _gpio_bank[gpio >> 5]; } + bool _gpio_valid(int gpio) { return (gpio < MAX_GPIOS) ? true : false; } + int _get_gpio_index(int gpio) { return gpio & 0x1f; } + + + inline void _irq_signal_send(int gpio) + { + if (_sign[gpio].valid()) + { + if (verbose) + PDBG("gpio=%d", gpio); + + Signal_transmitter transmitter(_sign[gpio]); + transmitter.submit(); + } + } + + inline void _irq_event(int gpio_bank, uint32_t status) + { + for(int i=0; i<32; i++) + { + if ( (status & (1 << i)) && irq_enabled[(gpio_bank<<5) + i] ) + _irq_signal_send( (gpio_bank<<5) + i ); + } + } + + void _handle_event_gpio1(); + void _handle_event_gpio2(); + void _handle_event_gpio3(); + void _handle_event_gpio4(); + void _handle_event_gpio5(); + void _handle_event_gpio6(); + +}; + + +Gpio::Driver::Driver() +: + _gpio1_mmio(GPIO1_MMIO_BASE, GPIO1_MMIO_SIZE), + _gpio1((addr_t)_gpio1_mmio.local_addr()), + _gpio2_mmio(GPIO2_MMIO_BASE, GPIO2_MMIO_SIZE), + _gpio2((addr_t)_gpio2_mmio.local_addr()), + _gpio3_mmio(GPIO3_MMIO_BASE, GPIO3_MMIO_SIZE), + _gpio3((addr_t)_gpio3_mmio.local_addr()), + _gpio4_mmio(GPIO4_MMIO_BASE, GPIO4_MMIO_SIZE), + _gpio4((addr_t)_gpio4_mmio.local_addr()), + _gpio5_mmio(GPIO5_MMIO_BASE, GPIO5_MMIO_SIZE), + _gpio5((addr_t)_gpio5_mmio.local_addr()), + _gpio6_mmio(GPIO6_MMIO_BASE, GPIO6_MMIO_SIZE), + _gpio6((addr_t)_gpio6_mmio.local_addr()) +{ + _gpio_bank[0] = &_gpio1; + _gpio_bank[1] = &_gpio2; + _gpio_bank[2] = &_gpio3; + _gpio_bank[3] = &_gpio4; + _gpio_bank[4] = &_gpio5; + _gpio_bank[5] = &_gpio6; + + for (int i = 0; i < NR_GPIOS; ++i) + { + uint32_t r = _gpio_bank[i]->read(); + if (verbose) + PDBG("GPIO%d ctrl=%08x", i+1, r); + } +} + + +bool Gpio::Driver::set_gpio_direction(int gpio, bool is_input) +{ + if (verbose) + PDBG("gpio=%d is_input=%d", gpio, is_input); + + if (!_gpio_valid(gpio)) + return false; + + Gpio_reg *gpio_reg = _get_gpio_bank(gpio); + + uint32_t value = gpio_reg->read(); + if (is_input) + value |= (1 << _get_gpio_index(gpio)); + else + value &= ~(1 << _get_gpio_index(gpio)); + gpio_reg->write(value); + + return true; +} + + +bool Gpio::Driver::set_gpio_dataout(int gpio, bool enable) +{ + if (verbose) + PDBG("gpio=%d enable=%d", gpio, enable); + + if (!_gpio_valid(gpio)) + return false; + + Gpio_reg *gpio_reg = _get_gpio_bank(gpio); + + if (enable) + gpio_reg->write(1 << _get_gpio_index(gpio)); + else + gpio_reg->write(1 << _get_gpio_index(gpio)); + + return true; +} + + +int Gpio::Driver::get_gpio_datain(int gpio) +{ + if (verbose) + PDBG("gpio=%d", gpio); + + if (!_gpio_valid(gpio)) + return -1; + + Gpio_reg *gpio_reg = _get_gpio_bank(gpio); + + uint32_t value = gpio_reg->read(); + + return (value & (1 << _get_gpio_index(gpio))) != 0 ; +} + + +bool Gpio::Driver::set_gpio_debounce_enable(int gpio, bool enable) +{ + if (verbose) + PDBG("gpio=%d enable=%d", gpio, enable); + + if (!_gpio_valid(gpio)) + return false; + + Gpio_reg *gpio_reg = _get_gpio_bank(gpio); + + uint32_t value = gpio_reg->read(); + if (enable) + value |= (1 << _get_gpio_index(gpio)); + else + value &= ~(1 << _get_gpio_index(gpio)); + gpio_reg->write(value); + + return true; +} + + +bool Gpio::Driver::set_gpio_debouncing_time(int gpio, unsigned int us) +{ + if (verbose) + PDBG("gpio=%d us=%d", gpio, us); + + if (!_gpio_valid(gpio)) + return false; + + unsigned char debounce; + + if (us < 32) + debounce = 0x01; + else if (us > 7936) + debounce = 0xff; + else + debounce = (us / 0x1f) - 1; + + Gpio_reg *gpio_reg = _get_gpio_bank(gpio); + + gpio_reg->write(debounce); + + return true; +} + + +bool Gpio::Driver::set_gpio_falling_detect(int gpio, bool enable) +{ + if (verbose) + PDBG("gpio=%d enable=%d", gpio, enable); + + if (!_gpio_valid(gpio)) + return false; + + Gpio_reg *gpio_reg = _get_gpio_bank(gpio); + + uint32_t value = gpio_reg->read(); + if (enable) + value |= (1 << _get_gpio_index(gpio)); + else + value &= ~(1 << _get_gpio_index(gpio)); + gpio_reg->write(value); + + return true; +} + + +bool Gpio::Driver::set_gpio_rising_detect(int gpio, bool enable) +{ + if (verbose) + PDBG("gpio=%d enable=%d", gpio, enable); + + if (!_gpio_valid(gpio)) + return false; + + Gpio_reg *gpio_reg = _get_gpio_bank(gpio); + + uint32_t value = gpio_reg->read(); + if (enable) + value |= (1 << _get_gpio_index(gpio)); + else + value &= ~(1 << _get_gpio_index(gpio)); + gpio_reg->write(value); + + return true; +} + + +bool Gpio::Driver::set_gpio_irq_enable(int gpio, bool enable) +{ + if (verbose) + PDBG("gpio=%d enable=%d", gpio, enable); + + if (!_gpio_valid(gpio)) + return false; + + Gpio_reg *gpio_reg = _get_gpio_bank(gpio); + + if (enable) + { + gpio_reg->write(1 << _get_gpio_index(gpio)); + gpio_reg->write(1 << _get_gpio_index(gpio)); + irq_enabled[gpio] = true; + } + else + { + gpio_reg->write(1 << _get_gpio_index(gpio)); + irq_enabled[gpio] = false; + } + + return true; +} + + +void Gpio::Driver::handle_event(int irq_number) +{ + if (verbose) + PDBG("IRQ #%d\n", irq_number-32); + switch(irq_number) + { + case GPIO1_IRQ: _handle_event_gpio1(); break; + case GPIO2_IRQ: _handle_event_gpio2(); break; + case GPIO3_IRQ: _handle_event_gpio3(); break; + case GPIO4_IRQ: _handle_event_gpio4(); break; + case GPIO5_IRQ: _handle_event_gpio5(); break; + case GPIO6_IRQ: _handle_event_gpio6(); break; + } +} + + +void Gpio::Driver::_handle_event_gpio1() +{ + int sts = _gpio1.read(); + if (verbose) + PDBG("GPIO1 IRQSTATUS=%08x\n", sts); + _irq_event(0, sts); + _gpio1.write(0xffffffff); +} + + +void Gpio::Driver::_handle_event_gpio2() +{ + int sts = _gpio2.read(); + if (verbose) + PDBG("GPIO2 IRQSTATUS=%08x\n", sts); + _irq_event(1, sts); + _gpio2.write(0xffffffff); +} + + +void Gpio::Driver::_handle_event_gpio3() +{ + int sts = _gpio3.read(); + if (verbose) + PDBG("GPIO3 IRQSTATUS=%08x\n", sts); + _irq_event(2, sts); + _gpio3.write(0xffffffff); +} + + +void Gpio::Driver::_handle_event_gpio4() +{ + int sts = _gpio4.read(); + if (verbose) + PDBG("GPIO4 IRQSTATUS=%08x\n", sts); + _irq_event(3, sts); + _gpio4.write(0xffffffff); +} + + +void Gpio::Driver::_handle_event_gpio5() +{ + int sts = _gpio5.read(); + if (verbose) + PDBG("GPIO5 IRQSTATUS=%08x\n", sts); + _irq_event(4, sts); + _gpio5.write(0xffffffff); +} + + +void Gpio::Driver::_handle_event_gpio6() +{ + int sts = _gpio6.read(); + if (verbose) + PDBG("GPIO6 IRQSTATUS=%08x\n", sts); + _irq_event(5, sts); + _gpio6.write(0xffffffff); +} + +#endif /* _DRIVER_H_ */ diff --git a/os/src/drivers/gpio/omap4/gpio.h b/os/src/drivers/gpio/omap4/gpio.h new file mode 100644 index 0000000000..9a87cf4faa --- /dev/null +++ b/os/src/drivers/gpio/omap4/gpio.h @@ -0,0 +1,44 @@ +/* + * \brief OMAP4 GPIO definitions + * \author Ivan Loskutov + * \date 2012-06-23 + */ + +/* + * Copyright (C) 2012 Ksys Labs LLC + * Copyright (C) 2012 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#ifndef _GPIO_H_ +#define _GPIO_H_ + +/* Genode includes */ +#include + +struct Gpio_reg : Genode::Mmio +{ + Gpio_reg(Genode::addr_t const mmio_base) : Genode::Mmio(mmio_base) { } + + struct Oe : Register<0x134, 32> {}; + struct Irqstatus_0 : Register<0x02c, 32> {}; + struct Irqstatus_set_0 : Register<0x034, 32> {}; + struct Irqstatus_clr_0 : Register<0x03c, 32> {}; + struct Ctrl : Register<0x130, 32> {}; + struct Leveldetect0 : Register<0x140, 32> {}; + struct Leveldetect1 : Register<0x144, 32> {}; + struct Risingdetect : Register<0x148, 32> {}; + struct Fallingdetect : Register<0x14c, 32> {}; + struct Debounceenable : Register<0x150, 32> {}; + struct Debouncingtime : Register<0x154, 32> + { + struct Time : Bitfield<0, 8> {}; + }; + struct Cleardataout : Register<0x190, 32> {}; + struct Setdataout : Register<0x194, 32> {}; + struct Datain : Register<0x138, 32> {}; +}; + +#endif /* _GPIO_H_ */ diff --git a/os/src/drivers/gpio/omap4/irq_handler.h b/os/src/drivers/gpio/omap4/irq_handler.h new file mode 100644 index 0000000000..04613447fa --- /dev/null +++ b/os/src/drivers/gpio/omap4/irq_handler.h @@ -0,0 +1,53 @@ +/* + * \brief Gpio irq-handler + * \author Ivan Loskutov + * \date 2012-06-23 + */ + +/* + * Copyright (C) 2012 Ksys Labs LLC + * Copyright (C) 2012 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#ifndef _IRQ_HANDLER_H_ +#define _IRQ_HANDLER_H_ + +/* Genode includes */ +#include +#include + +/* local includes */ +#include "driver.h" + +class Irq_handler : Genode::Thread<4096> +{ +private: + + int _irq_number; + Genode::Irq_connection _irq; + Gpio::Driver &_driver; + +public: + + Irq_handler(int irq_number, Gpio::Driver &driver) + : + _irq_number(irq_number), + _irq(irq_number), + _driver(driver) + { + start(); + } + + void entry() + { + while (1) { + _driver.handle_event(_irq_number); + _irq.wait_for_irq(); + } + } +}; + +#endif /* _IRQ_HANDLER_H_ */ diff --git a/os/src/drivers/gpio/omap4/main.cc b/os/src/drivers/gpio/omap4/main.cc new file mode 100644 index 0000000000..3b2eb79765 --- /dev/null +++ b/os/src/drivers/gpio/omap4/main.cc @@ -0,0 +1,223 @@ +/* + * \brief Gpio driver for the OMAP4 + * \author Ivan Loskutov + * \date 2012-06-23 + */ + +/* + * Copyright (C) 2012 Ksys Labs LLC + * Copyright (C) 2012 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +/* Genode includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* local includes */ +#include "driver.h" +#include "irq_handler.h" + + +namespace Gpio { + using namespace Genode; + class Session_component; +}; + + +class Gpio::Session_component : public Genode::Rpc_object +{ + private: + + Driver &_driver; + + Signal_context_capability _read_avail_sigh; + + public: + Session_component(Driver &driver) + : + _driver(driver) + { + } + + /************************************ + ** Gpio::Session interface ** + ************************************/ + + void direction_output(int gpio, bool enable) + { + _driver.set_gpio_dataout(gpio, enable); + _driver.set_gpio_direction(gpio, false); + } + + void direction_input(int gpio) + { + _driver.set_gpio_direction(gpio, true); + } + + void dataout(int gpio, bool enable) + { + _driver.set_gpio_dataout(gpio, enable); + } + + int datain(int gpio) + { + return _driver.get_gpio_datain(gpio); + } + + void debounce_enable(int gpio, bool enable) + { + _driver.set_gpio_debounce_enable(gpio, enable); + } + + void debouncing_time(int gpio, unsigned int us) + { + _driver.set_gpio_debouncing_time(gpio, us); + } + + void falling_detect(int gpio, bool enable) + { + _driver.set_gpio_falling_detect(gpio, enable); + } + + void rising_detect(int gpio, bool enable) + { + _driver.set_gpio_rising_detect(gpio, enable); + } + + void irq_enable(int gpio, bool enable) + { + _driver.set_gpio_irq_enable(gpio, enable); + } + + void irq_sigh(Signal_context_capability cap, int gpio) + { + _driver.register_signal(cap, gpio); + } +}; + + +int main(int, char **) +{ + using namespace Gpio; + + printf("--- omap4 gpio driver ---\n"); + + Driver driver; + + Irq_handler gpio1_irq(Driver::GPIO1_IRQ, driver); + Irq_handler gpio2_irq(Driver::GPIO2_IRQ, driver); + Irq_handler gpio3_irq(Driver::GPIO3_IRQ, driver); + Irq_handler gpio4_irq(Driver::GPIO4_IRQ, driver); + Irq_handler gpio5_irq(Driver::GPIO5_IRQ, driver); + Irq_handler gpio6_irq(Driver::GPIO6_IRQ, driver); + + /* + * Configure GPIO + * Example: + * + * + * + * + * + * num - GPIO pin number + * mode - input(I) or output(O) + * value - output level (1 or 0), only for output mode + */ + try { + Genode::Xml_node gpio_node = Genode::config()->xml_node().sub_node("gpio"); + for (;; gpio_node = gpio_node.next("gpio")) { + unsigned num; + char mode[2] = {0}; + unsigned value = 0; + bool value_ok; + + do { + try { + gpio_node.attribute("num").value(&num); + } + catch(Genode::Xml_node::Nonexistent_attribute) + { + PERR("Missing \"num\" attribute. Ignore node."); + break; + } + + try { + gpio_node.attribute("mode").value(mode, sizeof(mode)); + } + catch(Genode::Xml_node::Nonexistent_attribute) + { + PERR("Missing \"mode\" attribute. Ignore node."); + break; + } + + try { + value_ok = gpio_node.attribute("value").value(&value); + } + catch(Genode::Xml_node::Nonexistent_attribute) + { + value_ok = false; + } + + if (mode[0] == 'O' || mode[0] == 'o') + { + if (!value_ok) { + PERR("Missing \"value\" attribute for Output mode. Ignore node."); + break; + } + if (value > 1) { + PERR("Incorrect \"value\" attribute for Output mode. Ignore node."); + break; + } + driver.set_gpio_dataout(num, value); + driver.set_gpio_direction(num, false); + } else if (mode[0] == 'I' || mode[0] == 'i') { + driver.set_gpio_direction(num, true); + } else { + PERR("Incorrect value of \"mode\" attribute. Ignore node."); + break; + } + + PDBG("gpio %d mode %s value=%s", + num, mode, value_ok ? (value==0 ? "0" : value==1 ? "1" : "error") : "-" + ); + + } while(0); + if (gpio_node.is_last("gpio")) break; + } + } + catch (Genode::Xml_node::Nonexistent_sub_node) { + PERR("No GPIO config"); + } + + /* + * Initialize server entry point + */ + enum { STACK_SIZE = 4096 }; + static Cap_connection cap; + static Rpc_entrypoint ep(&cap, STACK_SIZE, "gpio_ep"); + + /* + * Let the entry point serve the gpio session and root interfaces + */ + static Session_component gpio_session(driver); + static Static_root gpio_root(ep.manage(&gpio_session)); + + /* + * Announce service + */ + env()->parent()->announce(ep.manage(&gpio_root)); + + Genode::sleep_forever(); + return 0; +} + diff --git a/os/src/drivers/gpio/omap4/target.mk b/os/src/drivers/gpio/omap4/target.mk new file mode 100644 index 0000000000..972fcffc32 --- /dev/null +++ b/os/src/drivers/gpio/omap4/target.mk @@ -0,0 +1,9 @@ + +TARGET = omap4_gpio_drv +REQUIRES = omap4 +SRC_CC = main.cc +LIBS = cxx env server signal +INC_DIR += $(PRG_DIR) + +vpath main.cc $(PRG_DIR) + diff --git a/os/src/test/gpio_drv/gpio_test.h b/os/src/test/gpio_drv/gpio_test.h new file mode 100644 index 0000000000..d89f5f1b28 --- /dev/null +++ b/os/src/test/gpio_drv/gpio_test.h @@ -0,0 +1,137 @@ +/* + * \brief Test of GPIO driver + * \author Ivan Loskutov + * \date 2012-06-23 + */ + +/* + * Copyright (C) 2012 Ksys Labs LLC + * Copyright (C) 2012 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#ifndef _GPIO_TEST_H_ +#define _GPIO_TEST_H_ + +#include +#include +#include +#include + +using namespace Genode; + +class Gpio_test +{ + public: + + enum { + LED1_GPIO = 7, + LED2_GPIO = 8, + BUTTON_GPIO = 121, + GPIO4_IRQ = 32 + 32, + }; + + private: + + Gpio::Connection _gpio; + + Signal_receiver sig_rec; + Signal_context sig_ctx; + + public: + Gpio_test(); + ~Gpio_test(); + + void wait_for_signal() + { + sig_rec.wait_for_signal(); + } + + bool polling_test(); + bool irq_test(); +}; + + +Gpio_test::Gpio_test() +{ + /* initialize GPIO_121 */ + _gpio.debouncing_time(BUTTON_GPIO, 31*100); + _gpio.debounce_enable(BUTTON_GPIO, 1); + + _gpio.irq_sigh(sig_rec.manage(&sig_ctx), BUTTON_GPIO); +} + + +Gpio_test::~Gpio_test() +{ +} + + +bool Gpio_test::polling_test() +{ + printf("---------- Polling test ----------\n"); + + printf("\nPush and hold button...\n"); + _gpio.dataout(LED1_GPIO, true); + _gpio.dataout(LED2_GPIO, false); + + volatile int gpio_state; + + do { + gpio_state = _gpio.datain(BUTTON_GPIO); + } while (gpio_state); + + printf("OK\n"); + + _gpio.dataout(LED1_GPIO, false); + _gpio.dataout(LED2_GPIO, true); + + printf("\nRelease button...\n"); + do { + gpio_state = _gpio.datain(BUTTON_GPIO); + } while (!gpio_state); + + printf("OK\n"); + + return true; +} + +bool Gpio_test::irq_test() +{ + printf("---------- IRQ test ----------\n"); + + _gpio.falling_detect(BUTTON_GPIO, 1); + _gpio.irq_enable(BUTTON_GPIO, 1); + + _gpio.dataout(LED1_GPIO, true); + _gpio.dataout(LED2_GPIO, false); + + printf("\nPush and hold button...\n"); + + wait_for_signal(); + + _gpio.irq_enable(BUTTON_GPIO, 0); + printf("OK\n"); + + _gpio.falling_detect(BUTTON_GPIO, 0); + _gpio.rising_detect(BUTTON_GPIO, 1); + _gpio.irq_enable(BUTTON_GPIO, 1); + + _gpio.dataout(LED1_GPIO, false); + _gpio.dataout(LED2_GPIO, true); + + printf("\nRelease button...\n"); + + wait_for_signal(); + + _gpio.irq_enable(BUTTON_GPIO, 0); + printf("OK\n"); + + _gpio.falling_detect(BUTTON_GPIO, 0); + _gpio.rising_detect(BUTTON_GPIO, 0); + return true; +} + +#endif /* _GPIO_TEST_H_ */ diff --git a/os/src/test/gpio_drv/main.cc b/os/src/test/gpio_drv/main.cc new file mode 100644 index 0000000000..d49b6d4978 --- /dev/null +++ b/os/src/test/gpio_drv/main.cc @@ -0,0 +1,32 @@ +/* + * \brief Test of GPIO driver + * \author Ivan Loskutov + * \date 2012-06-23 + */ + +/* + * Copyright (C) 2012 Ksys Labs LLC + * Copyright (C) 2012 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#include + +#include "gpio_test.h" + +int main(int, char **) +{ + printf("--- Pandaboard button (GPIO_121) test ---\n"); + + Gpio_test gpio_test; + + while(1) + { + gpio_test.polling_test(); + gpio_test.irq_test(); + } + + return 0; +} diff --git a/os/src/test/gpio_drv/target.mk b/os/src/test/gpio_drv/target.mk new file mode 100644 index 0000000000..055f00a2ce --- /dev/null +++ b/os/src/test/gpio_drv/target.mk @@ -0,0 +1,7 @@ +TARGET = test-omap4_gpio_drv +REQUIRES = omap4 +SRC_CC = main.cc +LIBS = cxx env thread signal +INC_DIR += $(PRG_DIR) + +vpath main.cc $(PRG_DIR)