Signed-off-by: Kuo-Jung Su <dant...@faraday-tech.com> --- hw/fttsc010.c | 239 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/fttsc010.h | 35 +++++++++ 2 files changed, 274 insertions(+) create mode 100644 hw/fttsc010.c create mode 100644 hw/fttsc010.h
diff --git a/hw/fttsc010.c b/hw/fttsc010.c new file mode 100644 index 0000000..2f5552e --- /dev/null +++ b/hw/fttsc010.c @@ -0,0 +1,239 @@ +/* + * Faraday FTTSC010 emulator. + * + * Copyright (c) 2012 Faraday Technology + * + * Written by Dante Su <dant...@faraday-tech.com> + * + * This code is licensed under the GPL. + */ + +#include "hw.h" +#include "qemu/timer.h" +#include "sysemu/sysemu.h" +#include "sysbus.h" +#include "ui/console.h" +#include "devices.h" + +#include "fttsc010.h" + +#define X_AXIS_DMAX 3470 +#define X_AXIS_MIN 290 +#define Y_AXIS_DMAX 3450 +#define Y_AXIS_MIN 200 + +#define ADS_XPOS(x, y) (X_AXIS_MIN + ((X_AXIS_DMAX * (x)) >> 15)) +#define ADS_YPOS(x, y) (Y_AXIS_MIN + ((Y_AXIS_DMAX * (y)) >> 15)) +#define ADS_Z1POS(x, y) (8) +#define ADS_Z2POS(x, y) ((1600 + ADS_XPOS(x, y)) * ADS_Z1POS(x, y) / ADS_XPOS(x, y)) + +typedef struct { + SysBusDevice busdev; + MemoryRegion iomem; + qemu_irq irq; + + uint64_t interval; + QEMUTimer *qtimer; + + int x, y; + int z1, z2; + + /* HW registers */ + uint32_t cr; + uint32_t isr; + uint32_t imr; + uint32_t csr; + uint32_t pfr; + uint32_t dcr; +} fttsc010_state; + +static inline void fttsc010_update_irq(void *opaque) +{ + fttsc010_state *s = (fttsc010_state *) opaque; + + if (s->imr & s->isr) + qemu_irq_raise(s->irq); + else + qemu_irq_lower(s->irq); +} + +static uint64_t fttsc010_mem_read(void *opaque, hwaddr addr, unsigned size) +{ + fttsc010_state *s = (fttsc010_state *) opaque; + + switch (addr) { + case REG_CR: + return s->cr; + case REG_ISR: + return s->isr; + case REG_IMR: + return s->imr; + case REG_VER: + return 0x00010000; + case REG_CSR: + return s->csr; + case REG_PFR: + return s->pfr; + case REG_DCR: + return s->dcr; + case REG_XYR: + return (s->x & 0x0fff) | ((s->y & 0x0fff) << 16); + case REG_ZR: + return (s->z1 & 0x0fff) | ((s->z2 & 0x0fff) << 16); + default: + break; + } + + return 0; +} + +static void fttsc010_mem_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) +{ + fttsc010_state *s = (fttsc010_state *) opaque; + + switch (addr) { + case REG_CR: + s->cr = (uint32_t)val; + if (s->cr & (3 << 30)) + qemu_mod_timer(s->qtimer, s->interval + qemu_get_clock_ns(vm_clock)); + else + qemu_del_timer(s->qtimer); + break; + case REG_ISR: + s->isr &= ~((uint32_t)val); + fttsc010_update_irq(s); + break; + case REG_IMR: + s->imr = (uint32_t)val; + fttsc010_update_irq(s); + break; + case REG_CSR: + s->csr = (uint32_t)val; + break; + case REG_PFR: + s->pfr = (uint32_t)val; + break; + case REG_DCR: + s->dcr = (uint32_t)val; + break; + default: + break; + } +} + +static const MemoryRegionOps fttsc010_mem_ops = { + .read = fttsc010_mem_read, + .write = fttsc010_mem_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void fttsc010_timer_tick(void *opaque) +{ + fttsc010_state *s = (fttsc010_state *) opaque; + + /* if auto-scan enabled */ + if (s->cr & (3 << 30)) { + s->isr |= (1 << 10); + /* turn it off, when it's under one-shot mode */ + if (s->cr & (1 << 30)) + s->cr &= ~(1 << 30); + } + + fttsc010_update_irq(s); + + qemu_mod_timer(s->qtimer, s->interval + qemu_get_clock_ns(vm_clock)); +} + +static void fttsc010_touchscreen_event(void *opaque, + int x, int y, int z, int buttons_state) +{ + fttsc010_state *s = (fttsc010_state *) opaque; + + if (buttons_state) { + x = 0x7fff - x; + s->x = ADS_XPOS(x, y); + s->y = ADS_YPOS(x, y); + s->z1 = ADS_Z1POS(x, y); + s->z2 = ADS_Z2POS(x, y); + } else { + s->z1 = 0; + s->z2 = 0; + } +} + +static void fttsc010_reset(DeviceState *d) +{ + fttsc010_state *s = DO_UPCAST(fttsc010_state, busdev.qdev, d); + + s->cr = 0; + s->isr = 0; + s->imr = 0; + s->csr = 0; + s->pfr = 0; + s->dcr = 0; + + s->x = 0; + s->y = 0; + s->z1 = 0; + s->z2 = 0; + + qemu_irq_lower(s->irq); +} + +static int fttsc010_init(SysBusDevice *dev) +{ + fttsc010_state *s = FROM_SYSBUS(fttsc010_state, dev); + + s->interval = (uint64_t)get_ticks_per_sec() >> 6; + s->qtimer = qemu_new_timer_ns(vm_clock, fttsc010_timer_tick, s); + + memory_region_init_io(&s->iomem, &fttsc010_mem_ops, s, "fttsc010", 0x1000); + sysbus_init_mmio(dev, &s->iomem); + sysbus_init_irq(dev, &s->irq); + + qemu_add_mouse_event_handler(fttsc010_touchscreen_event, s, 1, + "QEMU FTTSC010-driven Touchscreen"); + + return 0; +} + +static const VMStateDescription vmstate_fttsc010_regs = { + .name = "fttsc010", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(cr, fttsc010_state), + VMSTATE_UINT32(isr, fttsc010_state), + VMSTATE_UINT32(imr, fttsc010_state), + VMSTATE_UINT32(csr, fttsc010_state), + VMSTATE_UINT32(pfr, fttsc010_state), + VMSTATE_UINT32(dcr, fttsc010_state), + VMSTATE_END_OF_LIST(), + } +}; + +static void fttsc010_dev_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); + DeviceClass *k = DEVICE_CLASS(klass); + + sdc->init = fttsc010_init; + k->vmsd = &vmstate_fttsc010_regs; + k->reset = fttsc010_reset; + k->no_user = 1; +} + +static TypeInfo fttsc010_dev_info = { + .name = "fttsc010", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(fttsc010_state), + .class_init = fttsc010_dev_class_init, +}; + +static void fttsc010_register_types(void) +{ + type_register_static(&fttsc010_dev_info); +} + +type_init(fttsc010_register_types) diff --git a/hw/fttsc010.h b/hw/fttsc010.h new file mode 100644 index 0000000..c3756eb --- /dev/null +++ b/hw/fttsc010.h @@ -0,0 +1,35 @@ +/* + * Faraday FTTSC010 touchscreen driver + * + * This program is free software; you can redistribute it and/or modify + * it under the term of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Copyright 2009 Dante Su <dant...@gmail.com> + * + */ + +#ifndef FTTSC010_H +#define FTTSC010_H + +#define REG_CR 0x00 /* Control Register */ +#define REG_ISR 0x04 /* Interrupt Status Register */ +#define REG_IMR 0x08 /* Interrupt Mask Register */ +#define REG_VER 0x0C /* Version Register */ +#define REG_CSR 0x30 /* Clock & Sample Rate Register */ +#define REG_PFR 0x34 /* Panel Function Register */ +#define REG_DCR 0x38 /* Delay Control Register */ +#define REG_XYR 0x3C /* Touchscreen X,Y-Axis Register */ +#define REG_ZR 0x4C /* Touchscreen Z-Axis (Pressure) Register */ + +#endif -- 1.7.9.5 ********************* Confidentiality Notice ************************ This electronic message and any attachments may contain confidential and legally privileged information or information which is otherwise protected from disclosure. If you are not the intended recipient,please do not disclose the contents, either in whole or in part, to anyone,and immediately delete the message and any attachments from your computer system and destroy all hard copies. Thank you for your cooperation. ***********************************************************************