diff --git a/src/drivers/input/imx53_tablet/driver.h b/src/drivers/input/imx53_tablet/driver.h new file mode 100644 index 0000000..b9f86f7 --- /dev/null +++ b/src/drivers/input/imx53_tablet/driver.h @@ -0,0 +1,96 @@ +/* + * \brief Input-driver + * \author Stefan Kalkowski + * \date 2013-03-15 + */ + +/* + * Copyright (C) 2013-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__INPUT__SPEC__IMX53__DRIVER_H_ +#define _DRIVERS__INPUT__SPEC__IMX53__DRIVER_H_ + +/* Genode includes */ +#include +#include +#include + +/* local includes */ +#include +#include + +namespace Input { + class Tablet_driver; +} + + +class Input::Tablet_driver +{ + private: + + enum Gpio_irqs { + GPIO_TOUCH = 84, + GPIO_BUTTON = 132, + }; + + Event_queue &_ev_queue; + Gpio::Connection _gpio_ts; + Gpio::Connection _gpio_bt; + Genode::Irq_session_client _irq_ts; + Genode::Irq_session_client _irq_bt; + Genode::Io_signal_handler _ts_dispatcher; + Genode::Io_signal_handler _bt_dispatcher; + Touchscreen _touchscreen; + Buttons _buttons; + + void _handle_ts() + { + _touchscreen.event(_ev_queue); + _irq_ts.ack_irq(); + } + + void _handle_bt() + { + _buttons.event(_ev_queue); + _irq_bt.ack_irq(); + } + + Tablet_driver(Genode::Env &env, Event_queue &ev_queue) + : + _ev_queue(ev_queue), + _gpio_ts(env, GPIO_TOUCH), + _gpio_bt(env, GPIO_BUTTON), + _irq_ts(_gpio_ts.irq_session(Gpio::Session::LOW_LEVEL)), + _irq_bt(_gpio_bt.irq_session(Gpio::Session::FALLING_EDGE)), + _ts_dispatcher(env.ep(), *this, &Tablet_driver::_handle_ts), + _bt_dispatcher(env.ep(), *this, &Tablet_driver::_handle_bt), + _touchscreen(env), + _buttons(env) + { + /* GPIO touchscreen handling */ + _gpio_ts.direction(Gpio::Session::OUT); + _gpio_ts.write(true); + _gpio_ts.direction(Gpio::Session::IN); + + _irq_ts.sigh(_ts_dispatcher); + _irq_ts.ack_irq(); + + /* GPIO button handling */ + _gpio_bt.direction(Gpio::Session::OUT); + _gpio_bt.write(true); + _gpio_bt.direction(Gpio::Session::IN); + + _irq_bt.sigh(_bt_dispatcher); + _irq_bt.ack_irq(); + } + + public: + + static Tablet_driver* factory(Genode::Env &env, Event_queue &ev_queue); +}; + +#endif /* _DRIVERS__INPUT__SPEC__IMX53__DRIVER_H_ */ diff --git a/src/drivers/input/imx53_tablet/egalax_ts.h b/src/drivers/input/imx53_tablet/egalax_ts.h new file mode 100644 index 0000000..776e890 --- /dev/null +++ b/src/drivers/input/imx53_tablet/egalax_ts.h @@ -0,0 +1,96 @@ +/* + * \brief EETI eGalaxy touchscreen driver + * \author Stefan Kalkowski + * \date 2013-03-15 + */ + +/* + * Copyright (C) 2013-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__INPUT__SPEC__IMX53__EGALAX_TS_H_ +#define _DRIVERS__INPUT__SPEC__IMX53__EGALAX_TS_H_ + +/* Genode includes */ +#include +#include +#include +#include +#include + +/* local includes */ +#include + +namespace Input { + class Touchscreen; +} + + +class Input::Touchscreen { + + private: + + enum I2c_addresses { I2C_ADDR = 0x4 }; + enum Finger_state { PRESSED, RELEASED }; + + Irq_handler _irq_handler; + Genode::Attached_io_mem_dataspace _i2c_ds; + I2c::I2c _i2c; + Genode::uint8_t _buf[10]; + Finger_state _state; + + public: + + Touchscreen(Genode::Env &env) + : + _irq_handler(env, Imx53::I2C_3_IRQ), + _i2c_ds(env, Imx53::I2C_3_BASE, Imx53::I2C_3_SIZE), + _i2c((Genode::addr_t)_i2c_ds.local_addr(), + _irq_handler), + _state(RELEASED) + { + /* ask for touchscreen firmware version */ + Genode::uint8_t cmd[10] = { 0x03, 0x03, 0xa, 0x01, 0x41 }; + _i2c.send(I2C_ADDR, cmd, sizeof(cmd)); + } + + void event(Event_queue &ev_queue) + { + _i2c.recv(I2C_ADDR, _buf, sizeof(_buf)); + + /* ignore all events except of multitouch*/ + if (_buf[0] != 4) + return; + + int x = (_buf[3] << 8) | _buf[2]; + int y = (_buf[5] << 8) | _buf[4]; + + Genode::uint8_t state = _buf[1]; + bool valid = state & (1 << 7); + int id = (state >> 2) & 0xf; + int down = state & 1; + + if (!valid || id > 5) + return; /* invalid point */ + + x = 102400 / (3276700 / x); + y = 76800 / (3276700 / y); + + /* motion event */ + ev_queue.add(Input::Absolute_motion{x, y}); + + /* button event */ + if ((down && (_state == RELEASED)) || (!down && (_state == PRESSED))) { + + if (down) ev_queue.add(Input::Press {Input::BTN_LEFT}); + else ev_queue.add(Input::Release{Input::BTN_LEFT}); + + _state = down ? PRESSED : RELEASED; + } + } +}; + +#endif /* _DRIVERS__INPUT__SPEC__IMX53__EGALAX_TS_H_ */ diff --git a/src/drivers/input/imx53_tablet/i2c.h b/src/drivers/input/imx53_tablet/i2c.h new file mode 100644 index 0000000..c727a84 --- /dev/null +++ b/src/drivers/input/imx53_tablet/i2c.h @@ -0,0 +1,181 @@ +/* + * \brief Driver for the i.MX53 i2c controller + * \author Stefan Kalkowski + * \date 2013-03-15 + */ + +/* + * Copyright (C) 2013-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__INPUT__SPEC__IMX53__I2C_H_ +#define _DRIVERS__INPUT__SPEC__IMX53__I2C_H_ + +/* Genode includes */ +#include +#include + +/* local includes */ +#include "irq_handler.h" + +namespace I2c +{ + class I2c; +} + + +class I2c::I2c : Genode::Mmio +{ + private: + + struct Address : public Register<0x0, 8> + { + struct Addr : Bitfield<1,7> {}; + }; + + struct Freq_divider : public Register<0x4, 8> {}; + + struct Control : public Register<0x8, 8> + { + struct Repeat_start : Bitfield<2,1> {}; + struct Tx_ack_enable : Bitfield<3,1> {}; + struct Tx_rx_select : Bitfield<4,1> {}; + struct Master_slave_select : Bitfield<5,1> {}; + struct Irq_enable : Bitfield<6,1> {}; + struct Enable : Bitfield<7,1> {}; + }; + + struct Status : public Register<0xc, 8> + { + struct Rcv_ack : Bitfield<0,1> {}; + struct Irq : Bitfield<1,1> {}; + struct Slave_rw : Bitfield<2,1> {}; + struct Arbitration_lost : Bitfield<4,1> {}; + struct Busy : Bitfield<5,1> {}; + struct Addressed_as_slave : Bitfield<6,1> {}; + struct Data_transfer : Bitfield<7,1> {}; + }; + + struct Data : public Register<0x10, 8> { }; + + + class No_ack : Genode::Exception {}; + + Irq_handler & _irq_handler; + + void _busy() { while (!read()); } + + void _start() + { + /* clock enable */ + + write(0x2c); + write(0); + write(Control::Enable::bits(1)); + + while (!read()) { ; } + + write(1); + + _busy(); + + write(Control::Tx_rx_select::bits(1) | + Control::Tx_ack_enable::bits(1) | + Control::Irq_enable::bits(1) | + Control::Master_slave_select::bits(1) | + Control::Enable::bits(1)); + } + + void _stop() + { + write(0); + + /* clock disable */ + } + + void _write(Genode::uint8_t value) + { + write(value); + + do { _irq_handler.wait(); } + while (!read()); + + write(0); + if (read()) throw No_ack(); + + _irq_handler.ack(); + } + + public: + + I2c(Genode::addr_t const base, Irq_handler &irq_handler) + : Mmio(base), + _irq_handler(irq_handler) + { + write(0); + write(0); + } + + void send(Genode::uint8_t addr, const Genode::uint8_t *buf, + Genode::size_t num) + { + while (true) { + try { + _start(); + + _write(addr << 1); + for (Genode::size_t i = 0; i < num; i++) + _write(buf[i]); + + _stop(); + return; + } catch(No_ack) { } + _stop(); + } + } + + + void recv(Genode::uint8_t addr, Genode::uint8_t *buf, + Genode::size_t num) + { + while (true) { + try { + _start(); + _write(addr << 1 | 1); + write(0); + if (num > 1) + write(0); + read(); /* dummy read */ + + for (Genode::size_t i = 0; i < num; i++) { + + do { _irq_handler.wait(); } + while (!read()); + + write(0); + + if (i == num-1) { + write(0); + write(0); + while (read()) ; + } else if (i == num-2) { + write(1); + } + + buf[i] = read(); + _irq_handler.ack(); + } + + _stop(); + return; + } catch(No_ack) { } + _stop(); + } + } + +}; + +#endif /* _DRIVERS__INPUT__SPEC__IMX53__I2C_H_ */ diff --git a/src/drivers/input/imx53_tablet/irq_handler.h b/src/drivers/input/imx53_tablet/irq_handler.h new file mode 100644 index 0000000..bce7788 --- /dev/null +++ b/src/drivers/input/imx53_tablet/irq_handler.h @@ -0,0 +1,53 @@ +/* + * \brief Input-interrupt handler + * \author Josef Soentgen + * \date 2015-04-08 + */ + +/* + * Copyright (C) 2015-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 _IRQ_HANDLER_H_ +#define _IRQ_HANDLER_H_ + +/* Genode includes */ +#include + +class Irq_handler +{ + private: + + Genode::Env &_env; + Genode::Irq_connection _irq; + Genode::Io_signal_handler _handler; + + unsigned _sem_cnt = 1; + + void _handle() { _sem_cnt = 0; } + + public: + + Irq_handler(Genode::Env &env, int irq_number) + : + _env(env), _irq(env, irq_number), + _handler(env.ep(), *this, &Irq_handler::_handle) + { + _irq.sigh(_handler); + _irq.ack_irq(); + } + + void wait() + { + _sem_cnt++; + while (_sem_cnt > 0) + _env.ep().wait_and_dispatch_one_io_signal(); + } + + void ack() { _irq.ack_irq(); } +}; + +#endif /* _IRQ_HANDLER_H_ */ diff --git a/src/drivers/input/imx53_tablet/main.cc b/src/drivers/input/imx53_tablet/main.cc new file mode 100644 index 0000000..da0559f --- /dev/null +++ b/src/drivers/input/imx53_tablet/main.cc @@ -0,0 +1,65 @@ +/** + * \brief Input driver front-end + * \author Norman Feske + * \author Christian Helmuth + * \author Stefan Kalkowski + * \date 2006-08-30 + */ + +/* + * Copyright (C) 2006-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. + */ + +/* Genode includes */ +#include +#include +#include +#include +#include +#include + +/* local includes */ +#include + +using namespace Genode; + + +Input::Tablet_driver* Input::Tablet_driver::factory(Genode::Env &env, + Event_queue &ev_queue) +{ + static Input::Tablet_driver driver(env, ev_queue); + return &driver; +} + + +struct Main +{ + Genode::Env &env; + + Input::Session_component session { env, env.ram() }; + Input::Root_component root { env.ep().rpc_ep(), session }; + + Main(Genode::Env &env) : env(env) + { + Platform::Connection plat_drv { env }; + switch (plat_drv.revision()) { + case Platform::Session::SMD: + plat_drv.enable(Platform::Session::I2C_2); + plat_drv.enable(Platform::Session::I2C_3); + plat_drv.enable(Platform::Session::BUTTONS); + Input::Tablet_driver::factory(env, session.event_queue()); + break; + default: + warning("No input driver available for this board"); + } + + /* tell parent about the service */ + env.parent().announce(env.ep().manage(root)); + } +}; + + +void Component::construct(Genode::Env &env) { static Main main(env); } diff --git a/src/drivers/input/imx53_tablet/mpr121.h b/src/drivers/input/imx53_tablet/mpr121.h new file mode 100644 index 0000000..f1a734d --- /dev/null +++ b/src/drivers/input/imx53_tablet/mpr121.h @@ -0,0 +1,107 @@ +/* + * \brief Freescale MPR121 capacitative button driver + * \author Stefan Kalkowski + * \date 2013-03-15 + */ + +/* + * Copyright (C) 2013-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__INPUT__SPEC__IMX53__MPR121_H_ +#define _DRIVERS__INPUT__SPEC__IMX53__MPR121_H_ + +/* Genode includes */ +#include +#include +#include +#include +#include + +/* local includes */ +#include + +namespace Input { + class Buttons; +} + + +class Input::Buttons { + + private: + + enum { + I2C_ADDR = 0x5a, + }; + + enum Events { + RELEASE = 0, + BACK = 1, + HOME = 2, + MENU = 4, + POWER = 8, + }; + + Irq_handler _irq_handler; + Genode::Attached_io_mem_dataspace _i2c_ds; + I2c::I2c _i2c; + Genode::uint8_t _state; + + public: + + Buttons(Genode::Env &env) + : + _irq_handler(env, Imx53::I2C_2_IRQ), + _i2c_ds(env, Imx53::I2C_2_BASE, Imx53::I2C_2_SIZE), + _i2c((Genode::addr_t)_i2c_ds.local_addr(), + _irq_handler), + _state(0) + { + static Genode::uint8_t init_cmd[][2] = { + {0x41, 0x8 }, {0x42, 0x5 }, {0x43, 0x8 }, + {0x44, 0x5 }, {0x45, 0x8 }, {0x46, 0x5 }, + {0x47, 0x8 }, {0x48, 0x5 }, {0x49, 0x8 }, + {0x4a, 0x5 }, {0x4b, 0x8 }, {0x4c, 0x5 }, + {0x4d, 0x8 }, {0x4e, 0x5 }, {0x4f, 0x8 }, + {0x50, 0x5 }, {0x51, 0x8 }, {0x52, 0x5 }, + {0x53, 0x8 }, {0x54, 0x5 }, {0x55, 0x8 }, + {0x56, 0x5 }, {0x57, 0x8 }, {0x58, 0x5 }, + {0x59, 0x8 }, {0x5a, 0x5 }, {0x2b, 0x1 }, + {0x2c, 0x1 }, {0x2d, 0x0 }, {0x2e, 0x0 }, + {0x2f, 0x1 }, {0x30, 0x1 }, {0x31, 0xff}, + {0x32, 0x2 }, {0x5d, 0x4 }, {0x5c, 0xb }, + {0x7b, 0xb }, {0x7d, 0xc9}, {0x7e, 0x82}, + {0x7f, 0xb4}, {0x5e, 0x84}}; + + /* initialize mpr121 touch button device */ + for (unsigned i = 0; i < sizeof(init_cmd)/2; i++) + _i2c.send(I2C_ADDR, init_cmd[i], 2); + } + + void event(Event_queue &ev_queue) + { + int buttons[] = { BACK, HOME, MENU, POWER }; + int codes[] = { Input::KEY_BACK, Input::KEY_HOME, + Input::KEY_MENU, Input::KEY_POWER}; + + Genode::uint8_t buf = 0; + _i2c.send(I2C_ADDR, &buf, 1); + _i2c.recv(I2C_ADDR, &buf, 1); + + for (unsigned i = 0; i < (sizeof(buttons)/sizeof(int)); i++) { + if ((_state & buttons[i]) == (buf & buttons[i])) + continue; + + Input::Keycode const key = Input::Keycode(codes[i]); + + if (buf & buttons[i]) ev_queue.add(Input::Press {key}); + else ev_queue.add(Input::Release{key}); + }; + _state = buf; + } +}; + +#endif /* _DRIVERS__INPUT__SPEC__IMX53__MPR121_H_ */ diff --git a/src/drivers/input/imx53_tablet/target.mk b/src/drivers/input/imx53_tablet/target.mk new file mode 100644 index 0000000..cdf0b9d --- /dev/null +++ b/src/drivers/input/imx53_tablet/target.mk @@ -0,0 +1,6 @@ +TARGET = imx53_tablet_input_drv +REQUIRES = arm_v7 +SRC_CC = main.cc +LIBS = base +INC_DIR += $(PRG_DIR) +INC_DIR += $(call select_from_repositories,include/spec/imx53) diff --git a/src/drivers/pwm/imx53/main.cc b/src/drivers/pwm/imx53/main.cc new file mode 100644 index 0000000..ddf86af --- /dev/null +++ b/src/drivers/pwm/imx53/main.cc @@ -0,0 +1,86 @@ +/* + * \brief Pulse width modulation + * \author Stefan Kalkowski + * \date 2020-04-22 + */ + +/* + * Copyright (C) 2020 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. + */ + +/* Genode includes */ +#include +#include +#include +#include +#include + +struct Pwm : Genode::Mmio +{ + enum Clk_src { OFF, IPG, IPG_HIGHFREQ, IPG_32K }; + + struct Control : Register<0x0, 32> + { + struct Enable : Bitfield<0, 1> {}; + struct Clock_source : Bitfield<16, 2> {}; + struct Dbgen : Bitfield<22, 1> {}; + struct Waiten : Bitfield<23, 1> {}; + struct Dozen : Bitfield<24, 1> {}; + struct Stopen : Bitfield<25, 1> {}; + }; + + struct Sample : Register<0xc, 32> {}; + struct Period : Register<0x10,32> {}; + + Pwm(Genode::addr_t const mmio_base, + unsigned period, + unsigned sample, + Clk_src clk_src) + : Genode::Mmio(mmio_base) + { + write(period); + write(sample); + + Control::access_t ctrl = 0; + Control::Enable::set(ctrl, 1); + Control::Dbgen::set(ctrl, 1); + Control::Waiten::set(ctrl, 1); + Control::Dozen::set(ctrl, 1); + Control::Stopen::set(ctrl, 1); + Control::Clock_source::set(ctrl, clk_src); + write(ctrl); + } +}; + + +struct Main +{ + Genode::Env & _env; + Genode::Attached_rom_dataspace _config { _env, "config" }; + /** FIXME: currently use PWM2 of i.MX53, use platform driver in future **/ + Genode::Attached_io_mem_dataspace _ds { _env, 0x53fb8000, 0x4000 }; + Genode::Constructible _pwm {}; + + Main(Genode::Env &env) : _env(env) + { + Genode::log("--- i.MX53 Pulse-width-modulation driver ---"); + + Genode::Xml_node config = _config.xml(); + unsigned period = config.attribute_value("period", 0); + unsigned sample = config.attribute_value("sample", 0); + Genode::String<16> clk = config.attribute_value("clock_source", + Genode::String<16>()); + Pwm::Clk_src src = Pwm::OFF; + if (clk == "ipg") src = Pwm::IPG; + if (clk == "ipg_highfreq") src = Pwm::IPG_HIGHFREQ; + if (clk == "ipg_32k") src = Pwm::IPG_32K; + + _pwm.construct((Genode::addr_t)_ds.local_addr(), period, sample, src); + } +}; + + +void Component::construct(Genode::Env &env) { static Main main(env); } diff --git a/src/drivers/pwm/imx53/pwm.h b/src/drivers/pwm/imx53/pwm.h new file mode 100644 index 0000000..4bcc853 --- /dev/null +++ b/src/drivers/pwm/imx53/pwm.h @@ -0,0 +1,36 @@ +/* + * \brief Pulse width modulation + * \author Stefan Kalkowski + * \date 2013-03-05 + */ + +/* + * Copyright (C) 2013-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__PWM__IMX53__PWM_H_ +#define _DRIVERS__PWM__IMX53__PWM_H_ + +/* Genode includes */ +#include + +struct Pwm : Genode::Mmio +{ + struct Control : Register<0x0, 32> {}; + struct Sample : Register<0xc, 32> {}; + struct Period : Register<0x10,32> {}; + + Pwm(Genode::addr_t const mmio_base) : Genode::Mmio(mmio_base) { } + + void enable_display() + { + write(0x64); + write(0x64); + write(0x3c20001); + } +}; + +#endif /* _DRIVERS__PWM__IMX53__PWM_H_ */ diff --git a/src/drivers/pwm/imx53/target.mk b/src/drivers/pwm/imx53/target.mk new file mode 100644 index 0000000..1e0b684 --- /dev/null +++ b/src/drivers/pwm/imx53/target.mk @@ -0,0 +1,4 @@ +TARGET = imx53_pwd_drv +REQUIRES = arm_v7 +SRC_CC = main.cc +LIBS = base