|
|
1.1 ! root 1: /* ! 2: * TI ADS7846 / TSC2046 chip emulation. ! 3: * ! 4: * Copyright (c) 2006 Openedhand Ltd. ! 5: * Written by Andrzej Zaborowski <[email protected]> ! 6: * ! 7: * This code is licensed under the GNU GPL v2. ! 8: */ ! 9: ! 10: #include "hw.h" ! 11: #include "devices.h" ! 12: #include "console.h" ! 13: ! 14: struct ads7846_state_s { ! 15: qemu_irq interrupt; ! 16: ! 17: int input[8]; ! 18: int pressure; ! 19: int noise; ! 20: ! 21: int cycle; ! 22: int output; ! 23: }; ! 24: ! 25: /* Control-byte bitfields */ ! 26: #define CB_PD0 (1 << 0) ! 27: #define CB_PD1 (1 << 1) ! 28: #define CB_SER (1 << 2) ! 29: #define CB_MODE (1 << 3) ! 30: #define CB_A0 (1 << 4) ! 31: #define CB_A1 (1 << 5) ! 32: #define CB_A2 (1 << 6) ! 33: #define CB_START (1 << 7) ! 34: ! 35: #define X_AXIS_DMAX 3470 ! 36: #define X_AXIS_MIN 290 ! 37: #define Y_AXIS_DMAX 3450 ! 38: #define Y_AXIS_MIN 200 ! 39: ! 40: #define ADS_VBAT 2000 ! 41: #define ADS_VAUX 2000 ! 42: #define ADS_TEMP0 2000 ! 43: #define ADS_TEMP1 3000 ! 44: #define ADS_XPOS(x, y) (X_AXIS_MIN + ((X_AXIS_DMAX * (x)) >> 15)) ! 45: #define ADS_YPOS(x, y) (Y_AXIS_MIN + ((Y_AXIS_DMAX * (y)) >> 15)) ! 46: #define ADS_Z1POS(x, y) 600 ! 47: #define ADS_Z2POS(x, y) (600 + 6000 / ADS_XPOS(x, y)) ! 48: ! 49: static void ads7846_int_update(struct ads7846_state_s *s) ! 50: { ! 51: if (s->interrupt) ! 52: qemu_set_irq(s->interrupt, s->pressure == 0); ! 53: } ! 54: ! 55: uint32_t ads7846_read(void *opaque) ! 56: { ! 57: struct ads7846_state_s *s = (struct ads7846_state_s *) opaque; ! 58: ! 59: return s->output; ! 60: } ! 61: ! 62: void ads7846_write(void *opaque, uint32_t value) ! 63: { ! 64: struct ads7846_state_s *s = (struct ads7846_state_s *) opaque; ! 65: ! 66: switch (s->cycle ++) { ! 67: case 0: ! 68: if (!(value & CB_START)) { ! 69: s->cycle = 0; ! 70: break; ! 71: } ! 72: ! 73: s->output = s->input[(value >> 4) & 7]; ! 74: ! 75: /* Imitate the ADC noise, some drivers expect this. */ ! 76: s->noise = (s->noise + 3) & 7; ! 77: switch ((value >> 4) & 7) { ! 78: case 1: s->output += s->noise ^ 2; break; ! 79: case 3: s->output += s->noise ^ 0; break; ! 80: case 4: s->output += s->noise ^ 7; break; ! 81: case 5: s->output += s->noise ^ 5; break; ! 82: } ! 83: ! 84: if (value & CB_MODE) ! 85: s->output >>= 4; /* 8 bits instead of 12 */ ! 86: ! 87: break; ! 88: case 1: ! 89: s->cycle = 0; ! 90: break; ! 91: } ! 92: } ! 93: ! 94: static void ads7846_ts_event(void *opaque, ! 95: int x, int y, int z, int buttons_state) ! 96: { ! 97: struct ads7846_state_s *s = opaque; ! 98: ! 99: if (buttons_state) { ! 100: x = 0x7fff - x; ! 101: s->input[1] = ADS_XPOS(x, y); ! 102: s->input[3] = ADS_Z1POS(x, y); ! 103: s->input[4] = ADS_Z2POS(x, y); ! 104: s->input[5] = ADS_YPOS(x, y); ! 105: } ! 106: ! 107: if (s->pressure == !buttons_state) { ! 108: s->pressure = !!buttons_state; ! 109: ! 110: ads7846_int_update(s); ! 111: } ! 112: } ! 113: ! 114: static void ads7846_save(QEMUFile *f, void *opaque) ! 115: { ! 116: struct ads7846_state_s *s = (struct ads7846_state_s *) opaque; ! 117: int i; ! 118: ! 119: for (i = 0; i < 8; i ++) ! 120: qemu_put_be32(f, s->input[i]); ! 121: qemu_put_be32(f, s->noise); ! 122: qemu_put_be32(f, s->cycle); ! 123: qemu_put_be32(f, s->output); ! 124: } ! 125: ! 126: static int ads7846_load(QEMUFile *f, void *opaque, int version_id) ! 127: { ! 128: struct ads7846_state_s *s = (struct ads7846_state_s *) opaque; ! 129: int i; ! 130: ! 131: for (i = 0; i < 8; i ++) ! 132: s->input[i] = qemu_get_be32(f); ! 133: s->noise = qemu_get_be32(f); ! 134: s->cycle = qemu_get_be32(f); ! 135: s->output = qemu_get_be32(f); ! 136: ! 137: s->pressure = 0; ! 138: ads7846_int_update(s); ! 139: ! 140: return 0; ! 141: } ! 142: ! 143: static int ads7846_iid = 0; ! 144: ! 145: struct ads7846_state_s *ads7846_init(qemu_irq penirq) ! 146: { ! 147: struct ads7846_state_s *s; ! 148: s = (struct ads7846_state_s *) ! 149: qemu_mallocz(sizeof(struct ads7846_state_s)); ! 150: memset(s, 0, sizeof(struct ads7846_state_s)); ! 151: ! 152: s->interrupt = penirq; ! 153: ! 154: s->input[0] = ADS_TEMP0; /* TEMP0 */ ! 155: s->input[2] = ADS_VBAT; /* VBAT */ ! 156: s->input[6] = ADS_VAUX; /* VAUX */ ! 157: s->input[7] = ADS_TEMP1; /* TEMP1 */ ! 158: ! 159: /* We want absolute coordinates */ ! 160: qemu_add_mouse_event_handler(ads7846_ts_event, s, 1, ! 161: "QEMU ADS7846-driven Touchscreen"); ! 162: ! 163: ads7846_int_update(s); ! 164: ! 165: register_savevm("ads7846", ads7846_iid ++, 0, ! 166: ads7846_save, ads7846_load, s); ! 167: ! 168: return s; ! 169: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.