Commit fd5a3b33d1f19b4859a8c528097abdbc4463e7e0
1 parent
3e3d5815
Texas Instruments ADS7846 ADC chip.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2754 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
2 changed files
with
137 additions
and
0 deletions
hw/ads7846.c
0 → 100644
| 1 | +/* | ||
| 2 | + * TI ADS7846 chip emulation. | ||
| 3 | + * | ||
| 4 | + * Copyright (c) 2006 Openedhand Ltd. | ||
| 5 | + * Written by Andrzej Zaborowski <balrog@zabor.org> | ||
| 6 | + * | ||
| 7 | + * This code is licensed under the GNU GPL v2. | ||
| 8 | + */ | ||
| 9 | + | ||
| 10 | +#include <vl.h> | ||
| 11 | + | ||
| 12 | +struct ads7846_state_s { | ||
| 13 | + qemu_irq interrupt; | ||
| 14 | + | ||
| 15 | + int input[8]; | ||
| 16 | + int pressure; | ||
| 17 | + int noise; | ||
| 18 | + | ||
| 19 | + int cycle; | ||
| 20 | + int output; | ||
| 21 | +}; | ||
| 22 | + | ||
| 23 | +/* Control-byte bitfields */ | ||
| 24 | +#define CB_PD0 (1 << 0) | ||
| 25 | +#define CB_PD1 (1 << 1) | ||
| 26 | +#define CB_SER (1 << 2) | ||
| 27 | +#define CB_MODE (1 << 3) | ||
| 28 | +#define CB_A0 (1 << 4) | ||
| 29 | +#define CB_A1 (1 << 5) | ||
| 30 | +#define CB_A2 (1 << 6) | ||
| 31 | +#define CB_START (1 << 7) | ||
| 32 | + | ||
| 33 | +#define X_AXIS_DMAX 3680 | ||
| 34 | +#define X_AXIS_MIN 150 | ||
| 35 | +#define Y_AXIS_DMAX 3640 | ||
| 36 | +#define Y_AXIS_MIN 190 | ||
| 37 | + | ||
| 38 | +#define ADS_VBAT 2000 | ||
| 39 | +#define ADS_VAUX 2000 | ||
| 40 | +#define ADS_TEMP0 2000 | ||
| 41 | +#define ADS_TEMP1 3000 | ||
| 42 | +#define ADS_XPOS(x, y) (X_AXIS_MIN + ((X_AXIS_DMAX * (x)) >> 15)) | ||
| 43 | +#define ADS_YPOS(x, y) (Y_AXIS_MIN + ((Y_AXIS_DMAX * (y)) >> 15)) | ||
| 44 | +#define ADS_Z1POS(x, y) 600 | ||
| 45 | +#define ADS_Z2POS(x, y) (600 + 6000 / ADS_XPOS(x, y)) | ||
| 46 | + | ||
| 47 | +static void ads7846_int_update(struct ads7846_state_s *s) | ||
| 48 | +{ | ||
| 49 | + if (s->interrupt) | ||
| 50 | + qemu_set_irq(s->interrupt, s->pressure == 0); | ||
| 51 | +} | ||
| 52 | + | ||
| 53 | +uint32_t ads7846_read(void *opaque) | ||
| 54 | +{ | ||
| 55 | + struct ads7846_state_s *s = (struct ads7846_state_s *) opaque; | ||
| 56 | + | ||
| 57 | + return s->output; | ||
| 58 | +} | ||
| 59 | + | ||
| 60 | +void ads7846_write(void *opaque, uint32_t value) | ||
| 61 | +{ | ||
| 62 | + struct ads7846_state_s *s = (struct ads7846_state_s *) opaque; | ||
| 63 | + | ||
| 64 | + switch (s->cycle ++) { | ||
| 65 | + case 0: | ||
| 66 | + if (!(value & CB_START)) { | ||
| 67 | + s->cycle = 0; | ||
| 68 | + break; | ||
| 69 | + } | ||
| 70 | + | ||
| 71 | + s->output = s->input[(value >> 4) & 7]; | ||
| 72 | + | ||
| 73 | + /* Imitate the ADC noise, some drivers expect this. */ | ||
| 74 | + s->noise = (s->noise + 3) & 7; | ||
| 75 | + switch ((value >> 4) & 7) { | ||
| 76 | + case 1: s->output += s->noise ^ 2; break; | ||
| 77 | + case 3: s->output += s->noise ^ 0; break; | ||
| 78 | + case 4: s->output += s->noise ^ 7; break; | ||
| 79 | + case 5: s->output += s->noise ^ 5; break; | ||
| 80 | + } | ||
| 81 | + | ||
| 82 | + if (value & CB_MODE) | ||
| 83 | + s->output >>= 4; /* 8 bits instead of 12 */ | ||
| 84 | + | ||
| 85 | + break; | ||
| 86 | + case 1: | ||
| 87 | + s->cycle = 0; | ||
| 88 | + break; | ||
| 89 | + } | ||
| 90 | +} | ||
| 91 | + | ||
| 92 | +static void ads7846_ts_event(void *opaque, | ||
| 93 | + int x, int y, int z, int buttons_state) | ||
| 94 | +{ | ||
| 95 | + struct ads7846_state_s *s = opaque; | ||
| 96 | + | ||
| 97 | + if (buttons_state) { | ||
| 98 | + s->input[1] = ADS_YPOS(x, y); | ||
| 99 | + s->input[3] = ADS_Z1POS(x, y); | ||
| 100 | + s->input[4] = ADS_Z2POS(x, y); | ||
| 101 | + s->input[5] = ADS_XPOS(x, y); | ||
| 102 | + } | ||
| 103 | + | ||
| 104 | + if (s->pressure == !buttons_state) { | ||
| 105 | + s->pressure = !!buttons_state; | ||
| 106 | + | ||
| 107 | + ads7846_int_update(s); | ||
| 108 | + } | ||
| 109 | +} | ||
| 110 | + | ||
| 111 | +struct ads7846_state_s *ads7846_init(qemu_irq penirq) | ||
| 112 | +{ | ||
| 113 | + struct ads7846_state_s *s; | ||
| 114 | + s = (struct ads7846_state_s *) | ||
| 115 | + qemu_mallocz(sizeof(struct ads7846_state_s)); | ||
| 116 | + memset(s, 0, sizeof(struct ads7846_state_s)); | ||
| 117 | + | ||
| 118 | + s->interrupt = penirq; | ||
| 119 | + | ||
| 120 | + s->input[0] = ADS_TEMP0; /* TEMP0 */ | ||
| 121 | + s->input[2] = ADS_VBAT; /* VBAT */ | ||
| 122 | + s->input[6] = ADS_VAUX; /* VAUX */ | ||
| 123 | + s->input[7] = ADS_TEMP1; /* TEMP1 */ | ||
| 124 | + | ||
| 125 | + /* We want absolute coordinates */ | ||
| 126 | + qemu_add_mouse_event_handler(ads7846_ts_event, s, 1, | ||
| 127 | + "QEMU ADS7846-driven Touchscreen"); | ||
| 128 | + | ||
| 129 | + ads7846_int_update(s); | ||
| 130 | + return s; | ||
| 131 | +} |
vl.h
| @@ -1500,6 +1500,12 @@ uint8_t nand_getio(struct nand_flash_s *s); | @@ -1500,6 +1500,12 @@ uint8_t nand_getio(struct nand_flash_s *s); | ||
| 1500 | 1500 | ||
| 1501 | #include "ecc.h" | 1501 | #include "ecc.h" |
| 1502 | 1502 | ||
| 1503 | +/* ads7846.c */ | ||
| 1504 | +struct ads7846_state_s; | ||
| 1505 | +uint32_t ads7846_read(void *opaque); | ||
| 1506 | +void ads7846_write(void *opaque, uint32_t value); | ||
| 1507 | +struct ads7846_state_s *ads7846_init(qemu_irq penirq); | ||
| 1508 | + | ||
| 1503 | /* PCMCIA/Cardbus */ | 1509 | /* PCMCIA/Cardbus */ |
| 1504 | 1510 | ||
| 1505 | struct pcmcia_socket_s { | 1511 | struct pcmcia_socket_s { |