mirror of
https://github.com/genodelabs/genode.git
synced 2025-06-13 04:38:20 +00:00
os: Synaptics DSX touch screen driver
Provides touch event service for i.MX8M Quad only issue #3900
This commit is contained in:
committed by
Christian Helmuth
parent
89972b11b7
commit
96eb83f19a
183
repos/os/src/drivers/touch/synaptics_dsx/i2c.h
Normal file
183
repos/os/src/drivers/touch/synaptics_dsx/i2c.h
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
/*
|
||||||
|
* \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 <util/mmio.h>
|
||||||
|
#include <timer_session/connection.h>
|
||||||
|
|
||||||
|
/* local includes */
|
||||||
|
#include "irq_handler.h"
|
||||||
|
|
||||||
|
namespace I2c
|
||||||
|
{
|
||||||
|
class I2c;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class I2c::I2c : Genode::Mmio
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
struct Address : public Register<0x0, 16>
|
||||||
|
{
|
||||||
|
struct Addr : Bitfield<1,7> {};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Freq_divider : public Register<0x4, 16> {};
|
||||||
|
|
||||||
|
struct Control : public Register<0x8, 16>
|
||||||
|
{
|
||||||
|
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, 16>
|
||||||
|
{
|
||||||
|
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, 16> { };
|
||||||
|
|
||||||
|
|
||||||
|
class No_ack : Genode::Exception {};
|
||||||
|
|
||||||
|
Irq_handler & _irq_handler;
|
||||||
|
|
||||||
|
void _busy() { while (!read<Status::Busy>()); }
|
||||||
|
|
||||||
|
void _start()
|
||||||
|
{
|
||||||
|
/* clock enable */
|
||||||
|
/* input root 90 is 25Mhz target is 400Khz, divide by 64 */
|
||||||
|
write<Freq_divider>(0x2a);
|
||||||
|
write<Status>(0);
|
||||||
|
write<Control>(Control::Enable::bits(1));
|
||||||
|
|
||||||
|
while (!read<Control::Enable>()) { ; }
|
||||||
|
|
||||||
|
write<Control::Master_slave_select>(1);
|
||||||
|
|
||||||
|
_busy();
|
||||||
|
|
||||||
|
write<Control>(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<Control>(0);
|
||||||
|
|
||||||
|
/* clock disable */
|
||||||
|
}
|
||||||
|
|
||||||
|
void _write(Genode::uint8_t value)
|
||||||
|
{
|
||||||
|
write<Data>(value);
|
||||||
|
|
||||||
|
do { _irq_handler.wait(); }
|
||||||
|
while (!read<Status::Irq>());
|
||||||
|
|
||||||
|
write<Status::Irq>(0);
|
||||||
|
_irq_handler.ack();
|
||||||
|
|
||||||
|
if (read<Status::Rcv_ack>()) throw No_ack();
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
I2c(Genode::addr_t const base, Irq_handler &irq_handler)
|
||||||
|
: Mmio(base),
|
||||||
|
_irq_handler(irq_handler)
|
||||||
|
{
|
||||||
|
write<Control>(0);
|
||||||
|
write<Status>(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<Control::Tx_rx_select>(0);
|
||||||
|
if (num > 1)
|
||||||
|
write<Control::Tx_ack_enable>(0);
|
||||||
|
read<Data>(); /* dummy read */
|
||||||
|
|
||||||
|
for (Genode::size_t i = 0; i < num; i++) {
|
||||||
|
|
||||||
|
do { _irq_handler.wait(); }
|
||||||
|
while (!read<Status::Irq>());
|
||||||
|
|
||||||
|
write<Status::Irq>(0);
|
||||||
|
|
||||||
|
if (i == num-1) {
|
||||||
|
write<Control::Tx_rx_select>(0);
|
||||||
|
write<Control::Master_slave_select>(0);
|
||||||
|
while (read<Status::Busy>()) ;
|
||||||
|
} else if (i == num-2) {
|
||||||
|
write<Control::Tx_ack_enable>(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
buf[i] = read<Data>();
|
||||||
|
_irq_handler.ack();
|
||||||
|
}
|
||||||
|
|
||||||
|
_stop();
|
||||||
|
return;
|
||||||
|
} catch(No_ack) {
|
||||||
|
Genode::log("no ack");
|
||||||
|
_stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* _DRIVERS__INPUT__SPEC__IMX53__I2C_H_ */
|
53
repos/os/src/drivers/touch/synaptics_dsx/irq_handler.h
Normal file
53
repos/os/src/drivers/touch/synaptics_dsx/irq_handler.h
Normal file
@ -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 <irq_session/client.h>
|
||||||
|
|
||||||
|
class Irq_handler
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
Genode::Env &_env;
|
||||||
|
Genode::Irq_session_client _irq;
|
||||||
|
Genode::Io_signal_handler<Irq_handler> _handler;
|
||||||
|
|
||||||
|
unsigned _sem_cnt = 1;
|
||||||
|
|
||||||
|
void _handle() { _sem_cnt = 0; }
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Irq_handler(Genode::Env &env, Genode::Irq_session_capability irq)
|
||||||
|
:
|
||||||
|
_env(env), _irq(irq),
|
||||||
|
_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_ */
|
192
repos/os/src/drivers/touch/synaptics_dsx/main.cc
Normal file
192
repos/os/src/drivers/touch/synaptics_dsx/main.cc
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
/**
|
||||||
|
* \brief Synaptics DSX touch input
|
||||||
|
* \author Sebastian Sumpf
|
||||||
|
* \date 2020-09-03
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 <base/attached_dataspace.h>
|
||||||
|
#include <base/component.h>
|
||||||
|
#include <base/env.h>
|
||||||
|
|
||||||
|
#include <event_session/connection.h>
|
||||||
|
#include <gpio_session/connection.h>
|
||||||
|
#include <platform_session/connection.h>
|
||||||
|
#include <i2c.h>
|
||||||
|
|
||||||
|
using namespace Genode;
|
||||||
|
|
||||||
|
|
||||||
|
struct Finger_data
|
||||||
|
{
|
||||||
|
uint8_t status;
|
||||||
|
uint8_t x_lsb;
|
||||||
|
uint8_t x_msb;
|
||||||
|
uint8_t y_lsb;
|
||||||
|
uint8_t y_msb;
|
||||||
|
uint8_t wx;
|
||||||
|
uint8_t wy;
|
||||||
|
|
||||||
|
unsigned x() const
|
||||||
|
{
|
||||||
|
return 1080 - ((x_msb << 8) | x_lsb);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned y() const
|
||||||
|
{
|
||||||
|
return 1920 - ((y_msb << 8) | y_lsb);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dump() const
|
||||||
|
{
|
||||||
|
log("status: ", Hex(status),
|
||||||
|
" x_lsb: ", x_lsb, " x_msb: ", x_msb,
|
||||||
|
" y_lsb: ", y_lsb, " y_msb: ", y_msb,
|
||||||
|
" wx: ", wx, " wy: ", wy,
|
||||||
|
" x: ", x(),
|
||||||
|
" y: ", y());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct Synaptics
|
||||||
|
{
|
||||||
|
enum { FINGERS = 5, I2C_ADDR = 0x20, };
|
||||||
|
enum Gpio_irq { IRQ = 135 };
|
||||||
|
|
||||||
|
Genode::Env &env;
|
||||||
|
Irq_handler _i2c_irq_handler;
|
||||||
|
Attached_dataspace _i2c_ds;
|
||||||
|
I2c::I2c _i2c { (addr_t)_i2c_ds.local_addr<addr_t>(), _i2c_irq_handler };
|
||||||
|
Gpio::Connection _gpio { env, IRQ };
|
||||||
|
Irq_session_client _irq { _gpio.irq_session(Gpio::Session::LOW_LEVEL) };
|
||||||
|
Io_signal_handler<Synaptics> _irq_dispatcher { env.ep(), *this, &Synaptics::_handle_irq };
|
||||||
|
Event::Connection _event { env };
|
||||||
|
uint8_t _buf[10];
|
||||||
|
bool _button[FINGERS] { };
|
||||||
|
|
||||||
|
void _handle_event(Event::Session_client::Batch &batch)
|
||||||
|
{
|
||||||
|
/* retrieve status */
|
||||||
|
Finger_data fingers[FINGERS];
|
||||||
|
_buf[0] = 6;
|
||||||
|
_i2c.send(I2C_ADDR, _buf, 1);
|
||||||
|
_i2c.recv(I2C_ADDR, (uint8_t *)fingers, sizeof(fingers));
|
||||||
|
|
||||||
|
for (int i = 0; i < FINGERS; i++) {
|
||||||
|
Finger_data ¤t = fingers[i];
|
||||||
|
|
||||||
|
Input::Touch_id id { i };
|
||||||
|
|
||||||
|
if (current.status == 0) {
|
||||||
|
if (_button[i]) {
|
||||||
|
batch.submit(Input::Release{Input::BTN_LEFT});
|
||||||
|
batch.submit(Input::Touch_release{id});
|
||||||
|
_button[i] = false;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
batch.submit(Input::Absolute_motion { (int)current.x(), (int)current.y() });
|
||||||
|
batch.submit(Input::Touch { id, (float)current.x(), (float)current.y() });
|
||||||
|
|
||||||
|
if (_button[i] == false) {
|
||||||
|
batch.submit(Input::Press { Input::BTN_LEFT });
|
||||||
|
}
|
||||||
|
_button[i] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _handle_irq()
|
||||||
|
{
|
||||||
|
/* read device IRQ */
|
||||||
|
_buf[0] = 4;
|
||||||
|
_i2c.send(I2C_ADDR, _buf, 1);
|
||||||
|
_i2c.recv(I2C_ADDR, _buf, 2);
|
||||||
|
|
||||||
|
_event.with_batch([&] (Event::Session_client::Batch &batch) {
|
||||||
|
_handle_event(batch);
|
||||||
|
});
|
||||||
|
|
||||||
|
_irq.ack_irq();
|
||||||
|
}
|
||||||
|
|
||||||
|
Synaptics(Env &env, Dataspace_capability io_mem,
|
||||||
|
Irq_session_capability irq)
|
||||||
|
: env(env),
|
||||||
|
_i2c_irq_handler(env, irq),
|
||||||
|
_i2c_ds(env.rm(), io_mem)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* set page 0 */
|
||||||
|
_buf[0] = 0xff;
|
||||||
|
_buf[1] = 0;
|
||||||
|
_i2c.send(I2C_ADDR, _buf, 2);
|
||||||
|
|
||||||
|
/* enable interrupt */
|
||||||
|
_buf[0] = 0xf;
|
||||||
|
_buf[1] = 0x16;
|
||||||
|
_i2c.send(I2C_ADDR, _buf, 2);
|
||||||
|
|
||||||
|
/* set configured */
|
||||||
|
_buf[0] = 0xe;
|
||||||
|
_buf[1] = 0x84;
|
||||||
|
_i2c.send(I2C_ADDR, _buf, 2);
|
||||||
|
|
||||||
|
/* GPIO touchscreen handling */
|
||||||
|
_gpio.direction(Gpio::Session::IN);
|
||||||
|
|
||||||
|
_irq.sigh(_irq_dispatcher);
|
||||||
|
_irq.ack_irq();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct Main
|
||||||
|
{
|
||||||
|
Platform::Connection _platform_connection;
|
||||||
|
Constructible<Synaptics> _synaptics { };
|
||||||
|
|
||||||
|
Main(Env &env)
|
||||||
|
: _platform_connection(env)
|
||||||
|
{
|
||||||
|
using namespace Platform;
|
||||||
|
|
||||||
|
Device_capability cap;
|
||||||
|
try {
|
||||||
|
cap = _platform_connection.device_by_index(0);
|
||||||
|
} catch (...) {
|
||||||
|
error("Could not acquire device resources");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cap.valid() == false) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Device_client device { cap };
|
||||||
|
|
||||||
|
Dataspace_capability io_mem = device.io_mem_dataspace();
|
||||||
|
if (io_mem.valid() == false) {
|
||||||
|
Genode::warning("No 'io_mem' node present ... skipping");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Irq_session_capability irq = device.irq();
|
||||||
|
if (irq.valid() == false) {
|
||||||
|
Genode::warning("No 'irq' node present ... skipping");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_synaptics.construct(env, io_mem, irq);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void Component::construct(Genode::Env &env) { static Main main(env); }
|
5
repos/os/src/drivers/touch/synaptics_dsx/target.mk
Normal file
5
repos/os/src/drivers/touch/synaptics_dsx/target.mk
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
TARGET = imx8_synaptics_touch_drv
|
||||||
|
REQUIRES = arm_v8
|
||||||
|
SRC_CC = main.cc
|
||||||
|
LIBS = base
|
||||||
|
INC_DIR += $(PRG_DIR)
|
Reference in New Issue
Block a user